【问题标题】:Can this code be turned to use generators instead of lists?可以将此代码转换为使用生成器而不是列表吗?
【发布时间】:2016-07-19 20:47:16
【问题描述】:

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

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. 每个技能的数据在一个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() 方法都接受生成器,因此会节省大量内存。

编辑:另外,我不想循环播放器三遍。所以我很想在一个循环中以某种方式获得三个生成器。

【问题讨论】:

  • “三个大列表” – 我们实际谈论的是多大? player_datahero_data 似乎分别是 2 元组和 4 元组。如果您使用的是 Python 3,那么 skills_data_ 应该已经是 4 元组的生成器(因为您使用的是生成器表达式 (something for skill in hero.skills)
  • 玩家人数可以是 1 到 5000 人之间的任意值,英雄人数总是等于玩家人数,每个英雄可以拥有 4 到 15 种技能。我说的是players_dataheroes_dataskills_data 列表,希望将它们变成(tuple, tuple, generator[tuple]) 的生成器,而不是(tuple, tuple, generator[tuple]) 的列表。
  • 这很重要,因为一个包含 15 个项目的列表是 nothing (你从那里的生成器中一无所获)。甚至 5000 也不是那么多。您还必须考虑数据的来源。数据是否已经在内存中?还是你懒洋洋地从别的地方看?
  • 就您的问题而言,尚不清楚数据来自何处以及您究竟想将什么变成生成器。 player.get_serialized_data() 返回一个没有太多数据的三元组,所以这没有多大意义,所以我觉得你想把 _players.values() 变成一个生成器,但你根本没有显示 _players 是什么。所以我不知道我们应该如何帮助你。
  • 5000 名玩家并不多,但请记住,英雄的数量是相同的,每个英雄都有 4-15 种技能。那是约 100,000 件物品。数据 确实 已经存在,因此它已经在 RAM 中,但如果可能的话,我仍然希望避免使用这些列表。正如我所说,我想将当前的players_dataheroes_dataskills_data 变成生成器。它们目前是列表。

标签: python python-3.x generator


【解决方案1】:

如果您想在数据库上的单独操作中保存玩家、英雄和技能数据集(而不是为每个玩家及其关联的英雄和技能数据,或以某种方式并行保存)。

发电机在这里帮不了你。即使你能想出一个返回英雄和技能数据的生成器,它也需要在后台维护一个列表(或其他一些数据结构),除非你的三个数据库保存是并行发生的。您可能希望将您要求的内容与the implementation of itertools.tee 进行比较,后者会创建输入迭代器的多个“副本”。如果您并行地迭代副本(例如,zip)而不是一个一个地迭代,它只会节省空间。如果您逐个迭代副本,则本质上与将迭代器的内容复制到列表中并反复迭代相同。

【讨论】:

    猜你喜欢
    • 2017-12-23
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 2011-08-21
    • 2015-01-20
    • 2011-03-25
    相关资源
    最近更新 更多