2016-07-19 11 views
2

Ich habe eine Struktur wie diese (Pseudocode):Kann dieser Code verwendet werden, um Generatoren anstelle von Listen zu verwenden?

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 
} 

Nun, ich versuche es in einer Datenbank zu speichern, und ich habe meine Spieler eine get_serialized_data() Methode, die ein Tupel liefert etwa so:

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 
    ), 
) 

Schließlich ich Speicherung gleichzeitig jeden Daten in die Datenbank der Spieler, und mit drei Anrufe executemany() zu speichern:

  1. Every Daten des Spielers in einem executemany()
  2. Every Daten Helden in einer executemany()
  3. Every Daten Geschick in einem executemany()

Und hier ist mein Code, das zu tun:

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() 

Das "Problem", wie Sie sehen können, ist, dass ich drei große li konstruiere st. Kann man diese Listen irgendwie durch Generatoren ersetzen? Meine _database.save_X() Methoden alle akzeptieren Generatoren, so würde es eine Menge RAM sparen.

Edit: Auch möchte ich nicht die Spieler dreimal durchlaufen. Also würde ich gerne drei Generatoren während einer Schleife haben.

+0

* "drei große Listen" * - Wie groß reden wir eigentlich? 'player_data' und' hero_data' scheinen jeweils 2- und 4-Tupel zu sein. Und wenn Sie Python 3 verwenden, sollte 'skills_data_' bereits ein Generator von 4-Tupeln sein (da Sie einen Generator-Ausdruck' (etwas für Fähigkeiten in hero.skills) verwenden ') – poke

+0

Anzahl der Spieler kann alles sein eine bis 5000, die Anzahl der Helden ist immer gleich der Anzahl der Spieler und jeder Held kann zwischen 4 und 15 Fähigkeiten haben. Und ich spreche von den Listen 'players_data',' helds_data' und 'skills_data', in der Hoffnung, sie zu Generatoren von' (Tupel, Tupel, Generator [Tupel]) 'anstatt Listen von' (Tupel, Tupel, Generator [Tupel]) '. –

+0

Es ist relevant, weil eine Liste mit 15 Elementen * nichts * ist (Sie erhalten nichts von einem Generator dort). Und selbst 5000 ist nicht so viel. Sie müssen auch überlegen, woher die Daten stammen. Sind die Daten bereits im Speicher? Oder liest du es faul von woanders? – poke

Antwort

2

Es gibt keine Möglichkeit zu vermeiden, O(len(players)) Daten zu speichern, wenn Sie die Sätze Ihrer Spieler-, Helden- und Fertigkeitsdaten in separaten Vorgängen in der Datenbank speichern möchten (statt einen Vorgang für jeden Spieler mit seinem zugehörigen Helden und Fähigkeiten) Daten oder alles irgendwie parallel zu speichern).

Generatoren werden Ihnen hier nicht helfen. Selbst wenn Sie einen Generator entwickeln würden, der die Helden- und Fähigkeitsdaten zurückgibt, müsste er eine Liste (oder eine andere Datenstruktur) im Hintergrund behalten, außer wenn Ihre drei Datenbanksicherungen parallel ablaufen. Vielleicht möchten Sie vergleichen, was Sie wünschen, , die mehrere "Kopien" eines Eingabe-Iterators erstellt. Es ist nur platzsparend, wenn Sie die Kopien parallel durchlaufen (z. B. zip) und nicht nacheinander. Wenn Sie nacheinander über die Kopien iterieren, ist dies im Wesentlichen das Gleiche wie das Kopieren des Inhalts des Iterators in eine Liste und das wiederholte Iterieren.