2016-11-28 89 views
10

我認爲我知道變量和生成器如何在Python中很好地工作。
但是,下面的代碼讓我感到困惑。類中生成器的變量範圍

from __future__ import print_function 

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

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

當運行該代碼(Python的2)中,表示:

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 

在Python 3,它說NameError: name 'x' is not defined
但是,當我運行:

from __future__ import print_function 

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

a = A() 
print(a.lst) 

該代碼在Python 3中不起作用,但它在Python 2中或在函數這樣

from __future__ import print_function 

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

print(list(func())) 

此代碼的工作以及在Python 2和Python 3或在模塊水平

from __future__ import print_function 

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

print(list(gen)) 

代碼工作以及在Python 2和Python 3太。

爲什麼它在class錯?

回答

5

正如其他回答說,這是True,這是因爲它是靜態變量。但是,這不僅僅是限制你的代碼工作的屬性。實際原因是變量的範圍和它執行的範圍。例如,創建一個類:如果你訪問它的類屬性A.xA.y

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

,它會工作。因爲在初始化y時,x被替換爲表達式x+1中的值。由於x的範圍在課堂內。

然而這不會發生在發電機的情況下。即在例如:

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

這樣做list(a.gen),它是在類的外部執行(如發電機在運行時求值)和用於x在當前範圍的參考檢查。由於x未在該範圍內初始化,所以會引發錯誤。

當您明確初始化x=4時,它可以工作,因爲現在生成器表達式的值可以使用它的值x

爲了使您的發電機表達的工作,因爲被別人說你必須將它定義成:

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

聲明'它是在類之外執行的(因爲生成器在運行時被評估)並且在當前範圍**中檢查x **的引用可能有爭議。看到這個http://ideone.com/bgef81結果是[6,6,6],而不是[5,5,5],爲什麼? – WeizhongTu

6

由於x是一個類屬性(靜態變量),其可以訪問等,

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

這裏甚至gen是另一個類的屬性,這意味着,

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

由於發生器已經耗盡,因此這會導致空。


這是因爲只有當你發出 a.gen,當不會是它能夠解析名稱 x發電機進行評估。

+0

我認爲'x'是_class variable_不是一個靜態變量?我錯了嗎? –

+0

這不完全是「真」。將'gen'替換爲'y = x + 1'。然後像'A.y'那樣訪問它。它會工作。爲什麼它不適用於'gen'? –

+2

@MoinuddinQuadri當'y = x + 1'時,在處理'class'語句的主體時設置'y'的值時立即*查找*的值。 '(x for _ in range(3))'創建一個生成器表達式,其實體不會被計算,直到您真正嘗試從結果生成器中消耗值。也就是說,'x'的查找發生在'class'語句之外。 – chepner