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相同)

所以现在记录了对于任何可变序列类型ss += ts.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 的行为是不是记录在任何地方?

Python3的List操作和方法

python zip函数的用法

Python中的iterable该怎么理解

python中sorted函数的理解(对list列表排序,对dict字典排序)

Python中list总结