2016-11-28 11 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)を実行し、それは言う:私が実行したときにはPython 3では

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 

を、それが、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にうまく機能またはコードが過度のPython 2とPython 3にうまく機能

from __future__ import print_function 

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

print(list(gen)) 

モジュールレベルでのように機能します。

なぜ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) 
[] 

これは、ジェネレータがすでに使い果たされているため、空になります。あなたは名前xを解決することはできませんa.genを発行した場合にのみ発生装置が評価されるため


は、これが起こります。

+0

私は 'X'は、_classのvariable_ない静的変数と思いましたか?私は間違っていますか? –

+0

これは完全に「True」ではありません。 'gen'を' y = x + 1'に置き換えます。その後、「A.y」のようにアクセスします。それが動作します。なぜそれが 'gen'で動作しないのですか? –

+2

@MoinuddinQuadri 'y = x + 1'では、' class'ステートメントの本体を処理しているときに 'y'が設定されている場合、' x'の値が直ちに検索*されます。 '(x for _ range(3))'は、生成されたジェネレータの値を実際に消費しようとするまで、ボディが評価されないジェネレータ式を作成します。つまり、 'x'の検索は' class'文の外側で行われます。 – chepner

1

これは、xがクラス変数であるためです。 Pythonでは、クラス変数は、self(インスタンスメソッドからのアクセスなど)またはクラス名でアクセスする必要があります。より詳細な議論については

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

    def call_me(self): 
     print self.x 

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

他の回答で述べたように Static class variables in PythonWhy is Python class not recognizing static variable