2012-06-12 12 views
7

ich eine Pull-Anforderung mit diesem Code vorgelegt:eckige Klammern nicht in Listenkomprehensionen erforderlich, wenn in einer Funktion

my_sum = sum([x for x in range(10)]) 

Einer der Gutachter vorgeschlagen, diese stattdessen:

my_sum = sum(x for x in range(10)) 

(der Unterschied ist, nur dass die eckigen Klammern fehlen).

Ich war überrascht, dass die zweite Form identisch zu sein scheint. Aber wenn ich versuchte, es in anderen Kontexten zu verwenden, wo das erste funktioniert, schlägt es fehl:

y = x for x in range(10) 
     ^SyntaxError !!! 

Sind die zwei Formen identisch? Gibt es einen wichtigen Grund, warum die eckigen Klammern in der Funktion nicht notwendig sind? Oder ist das nur etwas, das ich wissen muss?

+3

[Dieser Link] (http://wiki.python.org/moin/Generators) könnte auch nützlich sein. – jadkik94

+0

Es gibt auch Wörterbuch und Satzverfasser, falls Sie nicht von ihnen gehört haben. – Amr

Antwort

15

Dies ist ein Generatorausdruck. Verwenden Sie geschweifte Klammern, um es im eigenständigen Fall zu verwenden:

y = (x for x in range(10)) 

und y wird zu einem Generator. Sie können über Generatoren iterieren, so dass es dort funktioniert, wo ein iterabler Wert erwartet wird, z. B. die sum-Funktion.

Anwendungsbeispiele und Tücken:

>>> y = (x for x in range(10)) 
>>> y 
<generator object <genexpr> at 0x0000000001E15A20> 
>>> sum(y) 
45 

Seien Sie vorsichtig, wenn sie um Generatoren zu halten, können Sie nur einmal durch sie gehen. So nach der oben, wenn Sie versuchen, wieder sum zu verwenden, dies geschieht:

>>> sum(y) 
0 

Also, wenn Sie einen Generator passieren, wo eigentlich eine Liste oder ein Satz oder etwas ähnliches zu erwarten ist, muss man vorsichtig sein. Wenn die Funktion oder Klasse das Argument speichert und mehrmals versucht, darüber zu iterieren, treten Probleme auf. Zum Beispiel betrachten dies:

def foo(numbers): 
    s = sum(numbers) 
    p = reduce(lambda x,y: x*y, numbers, 1) 
    print "The sum is:", s, "and the product:", p 

es wird scheitern, wenn Sie es mit einem Generator Hand:

>>> foo(x for x in range(1, 10)) 
The sum is: 45 and the product: 1 

Sie können ganz einfach eine Liste aus den Werten erhalten einen Generator erzeugt:

>>> y = (x for x in range(10)) 
>>> list(y) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Sie kann dies verwenden, um das vorherige Beispiel zu beheben:

>>> foo(list(x for x in range(1, 10))) 
The sum is: 45 and the product: 362880 

Beachten Sie jedoch, dass Sie beim Erstellen einer Liste aus einem Generator jeden Wert speichern müssen. Dies kann viel mehr Speicher in Situationen, in denen Sie viele Elemente haben, verwenden.

Warum einen Generator in Ihrer Situation verwenden?

Die viel niedrigeren Speicherverbrauch ist der Grund, warum sum(generator expression) ist besser als sum(list): Der Generator-Version hat nur einen einzigen Wert zu speichern, während die Liste-Variante N Werte speichern hat. Daher sollten Sie immer einen Generator verwenden, bei dem Sie keine Nebenwirkungen befürchten.

+0

Auch Generatorausdrücke benötigen oft weniger Speicher, da keine Zwischenliste erstellt wird. –

2

Erste ist die Liste comprehnsion Wo zweite Generator Ausdruck

(x for x in range(10)) 
    <generator object at 0x01C38580> 
    >>> a = (x for x in range(10)) 
    >>> sum(a) 
    45 
    >>> 

Verwenden Klammer für Generatoren:

>>> y = (x for x in range(10)) 
>>> y 
<generator object at 0x01C3D2D8> 
>>> 
3

Sie sind nicht identisch.

Die erste Form,

[x for x in l] 

ist eine Liste Verständnis. Der andere ist ein Generator Ausdruck und so geschrieben:

(x for x in l) 

Es gibt einen Generator, keine Liste.

Wenn der Generatorausdruck das einzige Argument in einem Funktionsaufruf ist, können seine Klammern übersprungen werden.

Siehe PEP 289

0

Lesen Sie diese PEP: 289

Zum Beispiel wird der folgende Summencode eine vollständige Liste der Quadrate im Speicher aufbauen, über diese Werten durchlaufen, und wenn die Referenz nicht mehr benötigt werden löschen, um die Liste:

sum([x*x for x in range(10)]) 

Speicher einen Generator Ausdruck durch Verwendung stattdessen konserviert ist:

Wenn die Datenmengen größer werden, tendieren Generatorausdrücke dazu, besser zu arbeiten, da sie den Cache-Speicher nicht erschöpfen und es Python ermöglichen, Objekte zwischen Iterationen erneut zu verwenden.

Verwenden Stützenprodukt einen Generator:

>>> y = (x for x in range(10)) 
>>> y 
<generator object <genexpr> at 0x00AC3AA8> 
Verwandte Themen