Python list += iterable 的行为是不是记录在任何地方?
Posted
技术标签:
【中文标题】Python list += iterable 的行为是不是记录在任何地方?【英文标题】:Is the behaviour of Python's list += iterable documented anywhere?Python list += iterable 的行为是否记录在任何地方? 【发布时间】:2012-12-03 23:28:42 【问题描述】:在 Python 中,list += x
似乎适用于任何可迭代的x
:
In [6]: l = []
In [7]: l += [1]
In [8]: l += (2, 3)
In [9]: l += xrange(5)
In [10]: l
Out[10]: [1, 2, 3, 0, 1, 2, 3, 4]
这种行为是否记录在任何地方?
为了与list + x
对比,后者仅在x
也是list
时才有效。这在documentation 中有详细说明。
【问题讨论】:
我会寻找一些文档来支持它,但我相信在列表的情况下+=
运算符模仿extend
。我会看看能不能找到一些东西来证实这一点。
python.org/dev/peps/pep-0203
@AshwiniChaudhary:我实际上在发布问题之前查看了 PEP,但没有找到任何关于 +=
和列表的具体内容。有没有我忽略的部分?
@NPE 可能是这个p.boxnet.eu/16970,也来自同一个PEP:The
i' in __iadd__' stands for
in-place, and if you call the module
dis` on +=
然后你会看到它只是就地添加。
我发现的最接近的是__iadd__
documentation 中的注释“这些方法应该尝试就地执行操作(修改自我)[...]”。
【参考方案1】:
来自Guido van Rossum:
它的工作方式与
.extend()
相同,只是它也返回self
。一世 找不到解释这一点的文档。 :-(
以下是取自listobject.c
的相关源码:
list_inplace_concat(PyListObject *self, PyObject *other)
PyObject *result;
result = listextend(self, other);
if (result == NULL)
return result;
Py_DECREF(result);
Py_INCREF(self);
return (PyObject *)self;
我已提交错误报告以修复文档:http://bugs.python.org/issue16701
【讨论】:
哈,+1 - 你比我领先两节 :) 该问题要求提供此行为的文档。源代码不是文档,并且 PEP 没有(据我从略读和 grepping 中得知)为列表定义+=
的语义,只有回退行为(列表覆盖)。我是否遗漏了什么,或者您实际上没有回答这个问题? -1 现在。
@delnan 如果文档中确实缺少这个东西,文档也可能有错误。
“它没有记录”是一个有效的答案,我猜 ;-) 但这不是这个答案所说的。
@delnan PEP 确实帮助我找到了函数,它说序列有自己的增强分配方法。例如。 binaryfunc sq_inplace_concat;
【参考方案2】:
在 Python 3.4+ 和 Python 2.7 中为 now documented:
4.6.3。可变序列类型
下表中的操作是在可变序列类型上定义的。提供
collections.abc.MutableSequence
ABC 是为了更轻松地在自定义序列类型上正确实现这些操作。[如下]
s
是可变序列类型的实例,t
是任何可迭代对象,x
是满足 @ 施加的任何类型和值限制的任意对象987654326@(例如,bytearray
只接受满足值限制0 <= x <= 255
的整数)。
s.extend(t)
或s += t
用
t
的内容扩展s
(大部分与s[len(s):len(s)] = t
相同)
所以现在记录了对于任何可变序列类型s
,s += t
是s.extend(t)
的同义词。
【讨论】:
【参考方案3】:否(Guido confirms;感谢 Ashwini Chaudhary)。序列的+=
的行为通常是未指定的。我的结论是,规范不要求x + y
其中x
是一个列表,而y
其他一些可迭代是错误的(因此其他实现可以选择允许它),并且其他实现可以限制@ 987654327@ 要求同质操作数。
但是,不这样做的原因很明显:python 通常会尝试对操作数做正确的事情,而不是要求严格的类型相等。真正的谜团是为什么列表不允许异类添加。
更新:我从来没有真正考虑过非同质加法问题,主要是因为itertools.chain
几乎是该问题的完整解决方案。
欢迎那些更熟悉 Python 内部的人发表评论,以解释为什么加法必须是同质的。 (此处提问:Why must Python list addition be homogenous?)
【讨论】:
@NPE 我很惊讶地意识到这种行为没有记录在案。我从来没有真正质疑过非异类+
,主要是因为我想连接一个列表和其他可迭代对象,我使用itertools.chain
来避免复制的需要,除了与字符串有关的情况。
我认为最后一段值得单独提出一个 SO 问题。这个问题我也想了很久。【参考方案4】:
对于那里的性能怪胎,是的,+=
比 extend
快一点:
>>> from timeit import repeat
>>> min(repeat('a.extend((1,2,3,4,5,6,7))', 'a=[]'))
0.23489440699995612
>>> min(repeat('e((1,2,3,4,5,6,7))', 'a=[]; e = a.extend'))
0.2214308570000867
>>> min(repeat('a+=(1,2,3,4,5,6,7)', 'a=[]'))
0.21909333300027356
这是它与append
的比较:
>>> min(repeat('a.append(1)', 'a=[]'))
0.062107428999297554
>>> min(repeat('p(1)', 'a=[]; p = a.append'))
0.04968810399986978
>>> min(repeat('a+=(1,)', 'a=[]'))
0.0501599309991434
(在 Python 3.7 64 位、Windows 上测试)
【讨论】:
以上是关于Python list += iterable 的行为是不是记录在任何地方?的主要内容,如果未能解决你的问题,请参考以下文章
Python list += iterable 的行为是不是记录在任何地方?