这是“贪婪” + =保证列表的行为?
我偶尔会使用“技巧”来扩展列表,例如自身的映射版本,以有效计算2:
from operator import mul
powers = [1]
powers += map(mul, [2] * 10, powers)
print(powers) # prints [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
这取决于+=
立即从map <
+=
/代码>到列表,因此MAP
然后找到它,并且该过程继续进行。换句话说,它需要这样工作:
powers = [1]
for value in map(mul, [2] * 10, powers):
powers.append(value)
而不是首先计算和存储整个右侧,其中powers
最终成为[1,2]
:
powers = [1]
powers += list(map(mul, [2] * 10, powers))
是否可以保证它像它一样工作吗?我检查了“ noreferrer”>可变序列类型除了暗示s += t
和s.extend(t)
的等效性外,还要说出很多话。它确实是指,他的
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
if values is self:
values = list(values)
for v in values:
self.append(v)
def __iadd__(self, values):
self.extend(values)
return self
这确实表明确实是假定的可以像我想要的那样工作,但是某些源代码不像文档中的保证那样安全。
I occasionally use the "trick" to extend a list by a mapped version of itself, for example to efficiently compute powers of 2:
from operator import mul
powers = [1]
powers += map(mul, [2] * 10, powers)
print(powers) # prints [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
This relies on the +=
immediately appending each value from map
to the list, so that the map
then finds it and the procedure continues. In other words, it needs to work like this:
powers = [1]
for value in map(mul, [2] * 10, powers):
powers.append(value)
And not first compute and store the whole right-hand side like this, where powers
ends up being [1, 2]
:
powers = [1]
powers += list(map(mul, [2] * 10, powers))
Is it somewhere guaranteed that it works like it does? I checked the Mutable Sequence Types documentation but it doesn't say much about it other than implying equivalence of s += t
and s.extend(t)
. It does refer to MutableSequence
, whose source code includes this:
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
if values is self:
values = list(values)
for v in values:
self.append(v)
def __iadd__(self, values):
self.extend(values)
return self
This does suggest that it's indeed supposed to work like it does and like I want it, but some source code being what it is doesn't feel as safe as a guarantee in the documentation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我看不到任何测试或文档可以保证贪婪的行为;但是,我确实认为这是预期的行为,野外的代码依赖于此。
fwiw,
+=
带有列表等效等于list.extend.extend()
,因此您的“技巧”归结为:虽然我没有找到
>的保证+=
或扩展
,我们确实保证了列表迭代器允许在迭代时允许突变。
https://docs.python.org/3/library/stdtypes .html#common-sequence-operations :
I don't see any tests or docs that the greedy behavior is guaranteed; however, I do think it is the expected behavior and that code in the wild relies on it.
FWIW,
+=
with lists is equivalent tolist.extend()
, so your "trick" boils down to:While I haven't found a guarantee for
+=
orextend
, we do have a guarantee that the list iterator allows mutation while iterating.¹ So, this code is on firm ground:¹ See the second paragraph following the table at:
https://docs.python.org/3/library/stdtypes.html#common-sequence-operations: