简体   繁体   English

列表的python迭代器如何实际工作?

[英]How does python iterator for list actually works?

Let's say we have the following list and we are creating an iterator for it: 假设我们有以下列表,我们正在为它创建一个迭代器:

lst = [1,2,3]
itr = iter(lst)

Next lets say we are changing our list with completely different values: 接下来假设我们正在使用完全不同的值更改列表:

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

And if I we run the following loop: 如果我运行以下循环:

for x in itr:
   print x

We will get '1,2,3' . 我们将得到'1,2,3' But why? 但为什么? As far as I understand, iterator doesn't copy all values from iterating object. 据我所知,迭代器不会复制迭代对象的所有值。 At least iterator for list from three elements has the same size as a list of 100000 elements. 至少三个元素列表的迭代器与100000个元素的列表具有相同的大小。 sys.getsizeof(i) returns 64 . sys.getsizeof(i)返回64 How can iterator be so small by size and keep 'old' values of list? 迭代器如何通过大小如此小并保持列表的“旧”值?

The iterator itself contains a reference to the list. 迭代器本身包含对列表的引用。 Since lst is rebound instead of mutated, this reference does not change. 由于lst是反弹而不是变异,因此该引用不会改变。

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

The iterator references a list object not a name. 迭代器引用列表对象而不是名称。 So reassigning the name lst to another object does not affect the iterator in anyway; 因此, 名称lst 重新分配给另一个对象不会影响迭代器; names are bound to objects, and refer to objects, but the names are not the object themselves. 名称绑定到对象,并引用对象,但名称不是对象本身。

You can get a snoop of the object the iterator is referencing with gc.get_referents : 您可以使用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]

As you'll notice, the iterator is still referring to the first list object. 正如您将注意到的,迭代器仍然引用第一个列表对象。


The following reference will help you learn more about names and binding in Python: 以下参考将帮助您了解有关Python中的名称和绑定的更多信息:

Execution model - Naming and binding 执行模型 - 命名和绑定

Welcome to Python's object reference system. 欢迎使用Python的对象引用系统。 The variable names do not really have a deep relationship with the actual object stored in memory. 变量名与存储在内存中的实际对象实际上没有很深的关系。

Suppose you have a friend lst , and you hire a mugger iter to mug him. 假设你有一个朋友lst ,你雇一个抢劫犯 iter以抢劫他。 Now you tell the mugger that your friend is the third Jack in the telephone directory ( globals ). 现在你告诉抢劫犯,你的朋友是第三杰克在电话目录( 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 variable names are just tags, that refer to some object in space. NTL; DR :Python变量名只是标记,指的是空间中的某个对象。 When you call iter on the list named lst , the iterator object kind of gets the pointer to the actual object, and doesn't even now its name was lst . 当你在名为lstlist上调用iter时,迭代器对象类获取指向实际对象的指针,甚至现在它的名称都不是lst

If you can modify the original object, by calling append , extend , pop , remove , etc, the iterators behaviour will be affected. 如果您可以修改原始对象,通过调用appendextendpopremove等,迭代器行为将受到影响。 But when you assign a new value to lst , a new object is created (if it didn't previously exist), and lst simply starts pointing to that new object. 但是当你分配一个新的值lst ,创建一个新的对象(如果它以前不存在),以及lst只是开始指向这个新的对象。

The garbage collector will delete the original object if no other object is pointing to it ( itr is pointing to it in this case, so the original object won't be deleted yet). 如果没有其他对象指向它,垃圾收集器将删除原始对象(在这种情况下itr指向它,因此原始对象将不会被删除)。

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

Extra: 额外:

# 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

This doesn't have anything to do with object reference, the iterator just stores internally that it has iterated the complete list. 这与对象引用没有任何关系,迭代器只在内部存储它迭代完整列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM