这是“贪婪” + =保证列表的行为?

发布于 2025-01-27 04:28:46 字数 1438 浏览 4 评论 0原文

我偶尔会使用“技巧”来扩展列表,例如自身的映射版本,以有效计算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 += ts.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

荒岛晴空 2025-02-03 04:28:46

我看不到任何测试或文档可以保证贪婪的行为;但是,我确实认为这是预期的行为,野外的代码依赖于此。

fwiw,+=带有列表等效等于list.extend.extend(),因此您的“技巧”归结为:

>>> powers = [1]
>>> powers.extend(2*x for x in islice(powers, 10))
>>> powers
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

虽然我没有找到>的保证+=扩展,我们确实保证了列表迭代器允许在迭代时允许突变

>>> powers = [1]
>>> for x in powers:
        if len(powers) == 10:
            break
        powers.append(2 * x)

>>> powers
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]


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 to list.extend(), so your "trick" boils down to:

>>> powers = [1]
>>> powers.extend(2*x for x in islice(powers, 10))
>>> powers
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

While I haven't found a guarantee for += or extend, we do have a guarantee that the list iterator allows mutation while iterating.¹ So, this code is on firm ground:

>>> powers = [1]
>>> for x in powers:
        if len(powers) == 10:
            break
        powers.append(2 * x)

>>> powers
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

¹ See the second paragraph following the table at:
https://docs.python.org/3/library/stdtypes.html#common-sequence-operations:

Forward and reversed iterators over mutable sequences access values
using an index. That index will continue to march forward (or
backward) even if the underlying sequence is mutated. The iterator
terminates only when an IndexError or a StopIteration is encountered
(or when the index drops below zero).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文