2016-10-22 14 views
2

のは、我々は次のリストを持っているし、我々はそれのためのイテレータを作成しているとしましょう:リストのpythonイテレータはどのように実際に動作しますか?

lst = [1,2,3] 
itr = iter(lst) 
次は、我々は完全に異なる値を持つ私たちのリストを変更していると言うことができます

lst = ['a', 'b', 'c'] 

そして、私たちが実行した場合次のループ:

for x in itr: 
    print x 

'1,2,3'を取得します。しかし、なぜ?私が理解する限り、イテレータは反復オブジェクトからすべての値をコピーしません。少なくとも3つの要素のリストのイテレータは、100000要素のリストと同じサイズです。 sys.getsizeof(i)64を返します。イテレータはどのようにしてサイズが小さくて、リストの「古い」値を保持できますか?

+1

あなたはリストを変更していないので、まったく関係のない新しいものを作成しました。 – jonrsharpe

答えて

4

イテレータ自体には、リストへの参照が含まれています。 lstは突然変異したものの代わりにリバウンドしているので、この参照は変更されません。

>>> lst = [1, 2, 3] 
>>> itr = iter(lst) 
>>> lst[:] = ['a', 'b', 'c'] 
>>> for x in itr: 
... print x 
... 
a 
b 
c 
3

イテレータは名前ではなくリストオブジェクトを参照します。だからの名前を別のオブジェクトにlstに割り当てても、イテレータには何の影響もありません。名前はオブジェクトにバインドされ、オブジェクトを参照しますが、名前はオブジェクト自体ではありません。あなたはイテレータがgc.get_referentsで参照しているオブジェクトのスヌープを取得することができます

>>> import gc 
>>> lst = [1,2,3] 
>>> itr = iter(lst) # return an iterator for the list 
>>> lst = ['a', 'b', 'c'] # Bind name lst to another object 
>>> gc.get_referents(itr)[0] 
[1, 2, 3] 

あなたが気づくと、反復子はまだ最初のリストオブジェクトを参照しています。


次の参照は、あなたが名およびPythonでを結合についての詳細を学ぶのを助ける:

Execution model - Naming and binding

2

Pythonのオブジェクト参照システムへようこそ。変数名は実際にメモリに格納されている実際のオブジェクトと深い関係はありません。

は、あなたが友人lstがあると、あなたは彼をマグ強盗iterを雇います。今度は、あなたの友人が電話帳の第3のジャック(globals)であることを強盗に伝えます。

lst = [1, 2, 3] 
itr = iter(lst)  # iter object now points to the list pointed to by lst 
        # it doesn't care about its name (doesn't even knows its name actually) 

# Now the mugger has found the friend, and knows his address (the actual object in memory). 
# The mugger catches him, and takes his jacket. 
print itr.next() # outputs 1 

# Now the telephone directory was updated (yes it's updated very frequently). 
lst1 = lst    # your friend is now the fourth Jack 
lst = ['a', 'b', 'c'] # someone else is the third Jack now 
         # but mugger doesn't know, he won't see the directory again 

print itr.next()  # (output 2), mugger takes t-shirt, and leaves him for now 

# Meanwhile your friend buys new clothes. 
lst1.append(4)  # here the actual object pointed to by iter is updated 
lst1.append(5) 

# You call the mugger and say, don't leave him until he's got nothing. 
# The mugger goes full retard. 
for i in iter: 
    print i   # outputs 3, 4 and 5 

NTL; DR:Pythonの変数名はスペースでいくつかのオブジェクトを参照するだけでタグです。 lstという名前のlistiterを呼び出すと、イテレータオブジェクトの種類は実際のオブジェクトへのポインタを取得しますが、現在の名前はlstでもありません。

あなたがappendextendpopremoveなどを呼び出すことによって、元のオブジェクトを変更することができた場合は、イテレータの動作が影響を受けることになります。しかし、新しい値をlstに割り当てると、新しいオブジェクトが作成されます(それが以前に存在しなかった場合)。lstは、単にその新しいオブジェクトを指し始めるだけです。

ガベージコレクタは、他のオブジェクトが指していない場合は元のオブジェクトを削除します(この場合はitrが指し示しているため、元のオブジェクトはまだ削除されません)。

http://foobarnbaz.com/2012/07/08/understanding-python-variables/

エクストラ:これは、オブジェクト参照とは何の関係もありません

# The friend goes and buys more clothes. 
lst1.extend([6, 7, 8]) 

# You call the mugger and ask him to take a shot at the friend again. 
itr.next() # But the mugger says, chill man he's got nothing now 
       # raises StopIteration 

、イテレータはちょうどそれが完全なリストを反復していることを内部的に格納します。

+0

すばらしい説明、ありがとう! – Paul

関連する問題