Izip_longest in itertools: was ist hier los

Ich bin zu kämpfen, um zu verstehen, wie der unten genannte Code funktioniert. Es ist von http://docs.python.org/library/itertools.html#itertools.izip_longest , und ist das rein-python-Äquivalent des izip_longest Iterators. Ich bin vor allem durch die Sentinel-Funktion verwirrt, wie funktioniert es?

def izip_longest(*args, **kwds): # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- fillvalue = kwds.get('fillvalue') def sentinel(counter = ([fillvalue]*(len(args)-1)).pop): yield counter() # yields the fillvalue, or raises IndexError fillers = repeat(fillvalue) iters = [chain(it, sentinel(), fillers) for it in args] try: for tup in izip(*iters): yield tup except IndexError: pass 

  • Summieren von verschachtelten Wörterbucheinträgen
  • Wie kann ich eine eindeutige Liste Zellen?
  • Wie gruppiere ich ähnliche Artikel in einer Liste?
  • Python keine Ausgabe bei Verwendung von pool.map_async
  • Itertools Äquivalent der verschachtelten Schleife "für x in xs: für y in ys ..."
  • Wie man die Anzahl aller möglichen Kombinationen für einen Bereich von Zahlen von 1 bis N berechnet?
  • Auto-Register Klassen Methoden mit Dekorateur
  • Python JSON komplexe Objekte (unter Berücksichtigung der Unterklassen)
  • Getter mit Nebenwirkung
  • Vermeiden Sie das Befehlsmuster in Python
  • Was ist der Unterschied zwischen Python-Dekorateuren und dem Dekorationsmuster?
  • Singleton über Module
  • 3 Solutions collect form web for “Izip_longest in itertools: was ist hier los”

    Ok, das können wir. Über den Wächter. Der Ausdruck ([fillvalue]*(len(args)-1)) erzeugt eine Liste, die einen ([fillvalue]*(len(args)-1)) für jeden iterable in args , minus eins. Also, für das obige Beispiel ['-'] . counter wird dann die pop dieser Liste zugewiesen. sentinel selbst ist ein Generator , der ein Element aus dieser Liste auf jeder Iteration springt. Sie können über jeden Iterator, der von sentinel genau einmal zurückgegeben wird, iterieren, und es wird immer fillvalue . Die Gesamtzahl der Gegenstände, die von allen von sentinel Iteratoren erbracht wurden, ist len(args) - 1 (dank Sven Marnach zur Klärung, dass ich es falsch verstanden habe).

    Schauen Sie sich das jetzt an:

     iters = [chain(it, sentinel(), fillers) for it in args] 

    Das ist der Trick. iters ist eine Liste, die einen Iterator für jeden iterable in args . Jeder dieser Iteratoren macht folgendes:

    1. Iterate über alle Artikel in der entsprechenden iterable von args .
    2. Iterate über Sentinel einmal, fillvalue .
    3. Wiederholen Sie den fillvalue für alle Ewigkeit.

    Nun, wie früher etabliert, können wir nur über alle Sentinels zusammen len(args)-1 mal, bevor es einen IndexError wirft. Das ist gut, denn einer der iterables ist der längste. Also, wenn wir auf den Punkt kommen, dass der IndexError aufgeworfen wird, bedeutet das, dass wir die Iteration über die längste iterable in args .

    Bitte schön.

    PS: Ich hoffe das ist verständlich.

    Die Funktion sentinel() gibt Iteratoren zurück, die genau einmal einen fillvalue . Die Gesamtzahl der fillvalue s, die von allen von sentinel() Iteratoren fillvalue ist auf n-1 , wobei n die Anzahl der Iteratoren ist, die an izip_longest() . Nachdem diese Anzahl von fillvalue s erschöpft ist, wird eine weitere Iteration über einen Iterator, der von sentinel() wird, einen IndexError .

    Diese Funktion wird verwendet, um festzustellen, ob alle Iteratoren erschöpft sind: Jeder Iterator ist chain() ed mit einem Iterator, der von sentinel() . Wenn alle Iteratoren erschöpft sind, wird ein von sentinel() Iterator zum n ten Mal IndexError , was zu einem IndexError , der das Ende von izip_longest() auslöst.

    Bisher habe ich erklärt, was sentinel() tut, nicht wie es funktioniert Wenn izip_longest() aufgerufen wird, wird die Definition von sentinel() ausgewertet. Bei der Auswertung der Definition wird auch das Standardargument an sentinel() ausgewertet, einmal pro Aufruf an izip_longest() . Der Code ist gleichbedeutend mit

     fillvalue_list = [fillvalue] * (len(args)-1) def sentinel(): yield fillvalue_list.pop() 

    Das Speichern in einem Standardargument anstatt in einer Variablen in einem umschließenden Bereich ist nur eine Optimierung, wie die Einbeziehung von .pop in das Standardargument ist, da es jedes Mal, wenn ein Iterator, der von sentinel() wird, aussieht .

    Die Definition von sentinel ist fast gleichbedeutend mit

     def sentinel(): yield ([fillvalue] * (len(args) - 1)).pop() 

    Außer dass es die popgebundene Methode (ein Funktionsobjekt) als Standardargument bekommt. Ein Standardargument wird zum Zeitpunkt der Funktionsdefinition ausgewertet, also einmal pro Aufruf an izip_longest anstatt einmal pro Aufruf an sentinel . Daher merkt sich das Funktionsobjekt die Liste [fillvalue] * (len(args) - 1) anstatt dieses neu in jedem Aufruf zu konstruieren.

    Python ist die beste Programmiersprache der Welt.