我有这样的结构(伪代码):
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()
来保存:
executemany()
executemany()
executemany()
这是我的代码:
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。
编辑:此外,我不想三次循环玩家。所以我很想在一个循环中以某种方式获得三台发电机。
答案 0 :(得分:2)
如果你想在数据库的不同操作中保存你的玩家,英雄和技能数据的集合,而不是为每个玩家的相关操作做一个操作,则无法避免存储O(len(players))
数据。英雄和技能数据,或者以某种方式并行保存它们。
发电机不会帮助你。即使您可以提出一个返回英雄和技能数据的生成器,它也需要在后台维护一个列表(或其他一些数据结构),除非您的三个数据库保存并行发生。您可能希望将您要求的内容与the implementation of itertools.tee
进行比较,Byte Buddy创建输入迭代器的几个“副本”。如果您并行(例如,zip
)而不是逐个遍历副本,那么它只是空间有效。如果你逐个遍历副本,它基本上与将迭代器的内容复制到列表中并重复迭代一样。