[英]list comprehension with generator
I used generator to generate some lists. 我用generator来生成一些列表。 However, it doesn't work like what I expected. 但是,它不像我预期的那样工作。 I first used numgen1 to to generate the list while it doesn't work properly. 我首先使用numgen1生成列表,但它无法正常工作。 And I switched to numgen2 which can gave me what I want properly. 然后我切换到numgen2,这可以给我正确的想法。 But both the numgen1 and numgen2 are basically the same (at least I think), why do they behave so differently? 但是numgen1和numgen2基本相同(至少我认为),为什么它们表现得如此不同? May anyone give me some explanations? 愿任何人给我一些解释吗?
def numgen1(start, end, delta):
curr=start
while curr[1] < end[1] or curr[2]<end[2]:
yield curr
curr[2] += delta
print 'Output1: ', [ i for i in numgen1([1,1,1],[1,1,5],1)]
def numgen2(start, end, delta):
curr=start
while curr[1] < end[1] or curr[2]<end[2]:
yield [curr[0], curr[1], curr[2]]
curr[2] += delta
print 'Output2: ', [ i for i in numgen2([1,1,1],[1,1,5],1)]
Here are the outputs. 这是输出。
Output1: [[1, 1, 5], [1, 1, 5], [1, 1, 5], [1, 1, 5]]
Output2: [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4]]
Follow up question: 跟进问题:
After reading the answer from unutbu, I write one more generator that is used to test what unutbu said. 在阅读unutbu的答案之后,我又写了一个用于测试unutbu所说的生成器。 But the generator doesn't behave as unutbu said. 但是发电机不像unutbu那样表现。 I am so confused about whether a generator is yielding a pointer or a copy of the value. 我对生成器是否产生指针或值的副本感到困惑。
def numgen3(start, end, delta):
curr=start
while curr<end:
yield curr
curr += delta
print list(numgen3(1,10,1))
Here is the output. 这是输出。 [1, 2, 3, 4, 5, 6, 7, 8, 9] [1,2,3,4,5,6,7,8,9]
This time I try to generate some numbers instead of some lists. 这次我尝试生成一些数字而不是一些列表。 But why aren't all the elements in the list 9? 但为什么不是列表9中的所有元素? I didn't create a new number, I just yield the same number (curr). 我没有创建一个新的数字,我只是产生相同的数字(curr)。 I expect the result of numgen3 should be similar to that of numgen1. 我期望numgen3的结果应该类似于numgen1的结果。
curr
is a list. curr
是一个清单。 curr[2] += delta
is modifying the list in-place . curr[2] += delta
正在就地修改列表。
When you yield curr
, you are yielding the same list over and over. 当你产生curr
,你会一遍又一遍地产生相同的列表。 When you print Output1
you are seeing this same list being printed many times. 当您打印Output1
您会看到同一列表被多次打印。
When you yield [curr[0], curr[1], curr[2]]
you are generating a new list. 当您产生[curr[0], curr[1], curr[2]]
您将生成一个新列表。 Thus, when you print Output2
, you see different values. 因此,当您打印Output2
,您会看到不同的值。
Notice how modifying curr
affects all items in result
, because result
is a list containing 3 items, each the same list curr
: 注意修改curr
如何影响result
所有项目 ,因为result
是一个包含3个项目的列表,每个项目都是相同的列表curr
:
curr = [0,0,0]
result = [curr for i in range(3)]
print(result)
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
curr[2] = 100
print(result)
# [[0, 0, 100], [0, 0, 100], [0, 0, 100]]
You could "fix" numgen1
by yielding list(curr)
since list(curr)
returns a new list with the same elements as in curr
(ie a "shallow copy"): 您可以通过产生list(curr)
来“修复” numgen1
,因为list(curr)
返回一个新的列表,其中包含与curr
相同的元素(即“浅拷贝”):
def numgen1(start, end, delta):
curr=start
while curr[1] < end[1] or curr[2]<end[2]:
yield list(curr)
curr[2] += delta
print 'Output1: ', [ i for i in numgen1([1,1,1],[1,1,5],1)]
yields 产量
Output1: [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4]]
Regarding numgen3
: 关于numgen3
:
def numgen3(start, end, delta):
curr=start
while curr<end:
yield curr
curr += delta
print list(numgen3(1,10,1))
It helps to make a mental distinction between mutable and immutable values. 它有助于在可变值和不可变值之间进行精神区分。 A list is mutable, numbers such as ints
are immutable. 列表是可变的,诸如ints
类的数字是不可变的。
Lists are containers. 列表是容器。 You can mutate its contents without changing the reference to the container. 您可以在不更改对容器的引用的情况下改变其内容。 Thus curr
is a list, curr[2] += delta
mutates the contents at index 2, but yield curr
yields the very same list. 因此curr
是一个列表, curr[2] += delta
改变索引2处的内容 ,但yield curr
产生相同的列表。
In numgen3
, curr
is an immutable int
. 在numgen3
, curr
是一个不可变的int
。 curr += delta
assigns curr
to a new immutable int
. curr += delta
将curr
分配给新的immutable int
。 It no longer references the same object. 它不再引用同一个对象。 yield curr
yields that value. yield curr
产生该值。 Those different values are accumulated in the list comprehension, and thus you see the result containing different values. 这些不同的值在列表推导中累积,因此您可以看到包含不同值的结果。
Here is another perspective on what it means to modify a list in-place : The modification is done in-place if the contents of the list change, while the memory address of the list itself does not change. 下面是什么意思修改就地列表另一个角度来看:修改在原地做,如果列表的内容发生变化,而列表中的内存地址本身并没有改变。
id(obj)
returns the memory address of the object obj
. id(obj)
返回对象obj
的内存地址。 Notice that modifying curr[2]
does not change the id
of curr
: 请注意,修改curr[2]
不会更改curr
的id
:
In [162]: curr = [0,0,0]
In [163]: id(curr)
Out[163]: 196192940
In [164]: curr[2] += 1
In [165]: curr
Out[165]: [0, 0, 1]
In [166]: id(curr)
Out[166]: 196192940
Compare that with what happens when you increment a variable assigned to an int
: 将其与增加分配给int
的变量时发生的情况进行比较:
In [191]: curr = 1
In [192]: id(curr)
Out[192]: 150597808
In [193]: curr += 1
In [194]: id(curr)
Out[194]: 150597796
Here, curr
is not being modified in-place. 这里, curr
没有就地修改。 curr
is simply being redirected to reference a new value at a new memory address. curr
被简单地重定向以在新的内存地址处引用新值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.