2016-11-28 4 views
10

Ich denke, dass ich weiß, wie Variablen und Generatoren in Python gut funktionieren.
Allerdings verwirrt mich der folgende Code.Variable Umfang in Generatoren in Klassen

from __future__ import print_function 

class A(object): 
    x = 4 
    gen = (x for _ in range(3)) 

a = A() 
print(list(a.gen)) 

Wenn Sie den Code (Python 2) laufen, heißt es:

Traceback (most recent call last): 
    File "Untitled 8.py", line 10, in <module> 
    print(list(a.gen)) 
    File "Untitled 8.py", line 6, in <genexpr> 
    gen = (x for _ in range(3)) 
NameError: global name 'x' is not defined 

In Python 3, heißt es NameError: name 'x' is not defined
aber, wenn ich laufe:

from __future__ import print_function 

class A(object): 
    x = 4 
    lst = [x for _ in range(3)] 

a = A() 
print(a.lst) 

Der Code funktioniert nicht in Python 3, aber in Python 2 oder in einem Funktion wie dies

from __future__ import print_function 

def func(): 
    x = 4 
    gen = (x for _ in range(3)) 
    return gen 

print(list(func())) 

Dieser Code auch in Python 2 und Python 3 oder auf Modulebene arbeitet

from __future__ import print_function 

x = 4 
gen = (x for _ in range(3)) 

print(list(gen)) 

Der Code funktioniert gut in Python 2 und Python 3 zu.

Warum ist es falsch in class?

Antwort

5

Wie in anderen Antwort erwähnt, ist es True, dass es geschieht, weil es statische Variable ist. Es ist jedoch nicht nur diese Eigenschaft, die den Code einschränkt. Der tatsächliche Grund ist der Umfang der Variablen und der Bereich, in dem sie ausgeführt wird. Erstellen Sie zum Beispiel eine Klasse als:

class A(object): 
    x = 999999 
    y = x +1 

Wenn Sie es Klasse Eigenschaften A.x und A.y zuzugreifen, wird es funktionieren.Weil zum Zeitpunkt der Initialisierung y, x der Wert in Ausdruck x+1 ersetzt wird. Da der Umfang von x innerhalb der Klasse lag.

Dies geschieht jedoch nicht bei Generatoren. das heißt in Ihrem Beispiel:

class A(object): 
    x = 4 
    gen = (x for _ in range(3)) 

Wenn Sie list(a.gen) tun, wird es außerhalb der Klasse ausgeführt und prüft, ob die Referenz x im aktuellen Bereich (wie Generatoren während der Laufzeit ausgewertet werden). Da x in diesem Bereich nicht initialisiert wird, wird ein Fehler ausgegeben.

Wenn Sie x=4 explizit initialisieren, funktioniert das, weil der Generatorausdruck nun den Wert x hat, für den er verwendet werden könnte.

Um Ihre Generator Ausdruck Arbeit zu machen, wie bereits von anderen erwähnt haben Sie es definieren mag:

class A(object): 
    x = 4 
    gen = (A.x for _ in range(3)) 
    # ^mentioning `A.x` is the value to access 
+0

Die Anweisung 'es wird außerhalb der Klasse ausgeführt (da Generatoren während der Laufzeit ausgewertet werden) und prüft auf die Referenz von x ** im aktuellen Bereich **' könnte argumentiert werden. Siehe http://ideone.com/bgef81 das Ergebnis ist [6,6,6], nicht [5,5,5], warum? – WeizhongTu

6

Da x ist ein Klassenattribut (statische Variable), die Sie wie Zugang,

Beispiel

>>> class A(object): 
...  x = 4 
...  gen = (A.x for _ in range(3)) 
... 
>>> a = A() 
>>> list(a.gen) 
[4, 4, 4] 

hier auch gen ist eine andere Klasse Attribut, das bedeutet, dass

>>> b = A() 
>>> list(b.gen) 
[] 

Dies gibt leer, weil der Generator bereits erschöpft ist.


Dies geschieht, weil der Generator nur ausgewertet, wenn Sie a.gen ausgeben, wenn es nicht in der Lage sein, den Namen x zu lösen.

+0

Ich dachte, dass 'X' ein _class war Variable_ keine statische Variable? Täusche ich mich? –

+0

Das ist nicht ganz "wahr". Ersetzen Sie "gen" durch "y = x + 1". Dann greife darauf wie 'A.y' zu. Es wird klappen. Warum funktioniert es nicht mit 'gen'? –

+2

@MoinuddinQuadri Mit 'y = x + 1' wird der Wert von' x' sofort * nachgeschlagen, wenn der Wert if 'y' gesetzt wird, während der Rumpf der 'class' Anweisung verarbeitet wird. '(x für _ im Bereich (3))' erstellt einen Generatorausdruck, dessen Körper erst ausgewertet wird, wenn Sie versuchen, Werte aus dem resultierenden Generator zu konsumieren. Das heißt, das Nachschlagen nach "x" erfolgt außerhalb der "class" -Anweisung. – chepner