可以将此代码转为使用生成器而不是列表吗?

时间:2016-07-19 20:47:16

标签: python python-3.x generator

我有这样的结构(伪代码):

class Player {
    steamid: str
    hero: Hero
}
class Hero {
    class_id: str
    level: int
    xp: int
    skills: list[Skill]
}
class Skill {
    class_id: str
    level: int
}

现在我正在尝试将它存储到一个数据库中,我给了我的播放器一个get_serialized_data()方法,它返回一个像这样的元组:

return (
    # players
    (steamid, hero.class_id),
    # heroes
    (steamid, hero.class_id, hero.level, hero.xp),
    # skills
    (
        (steamid, hero.class_id, skill.class_id, skill.level)
        for skill in hero.skills
    ),
)

最后,我同时将每个玩家的数据存储到数据库中,并使用三次调用executemany()来保存:

  1. 每个玩家的数据在一个executemany()
  2. 一个executemany()
  3. 中的每个英雄的数据
  4. 一个executemany()
  5. 中的每个技能数据

    这是我的代码:

    def save_all_data(*, commit=True):
        """Save every active player's data into the database."""
        players_data = []
        heroes_data = []
        skills_data = []
        for player in _players.values():
            player_data, hero_data, skills_data_ = player.get_serialized_data()
            players_data.append(player_data)
            heroes_data.append(heroes_data)
            skills_data.extend(skills_data_)
        _database.save_players(players_data)
        _database.save_heroes(heroes_data)
        _database.save_skills(skills_data)
        if commit:
            _database.commit()
    

    正如您所看到的,“问题”是我构建了三个大型列表。是否有可能以某种方式用发电机替换这些列表?我的_database.save_X()方法都接受生成器,因此可以节省大量RAM。

    编辑:此外,我不想三次循环玩家。所以我很想在一个循环中以某种方式获得三台发电机。

1 个答案:

答案 0 :(得分:2)

如果你想在数据库的不同操作中保存你的玩家,英雄和技能数据的集合,而不是为每个玩家的相关操作做一个操作,则无法避免存储O(len(players))数据。英雄和技能数据,或者以某种方式并行保存它们。

发电机不会帮助你。即使您可以提出一个返回英雄和技能数据的生成器,它也需要在后台维护一个列表(或其他一些数据结构),除非您的三个数据库保存并行发生。您可能希望将您要求的内容与the implementation of itertools.tee进行比较,Byte Buddy创建输入迭代器的几个“副本”。如果您并行(例如,zip)而不是逐个遍历副本,那么它只是空间有效。如果你逐个遍历副本,它基本上与将迭代器的内容复制到列表中并重复迭代一样。