【问题标题】: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。我会看看能不能找到一些东西来证实这一点。
  • @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 中的注释“这些方法应该尝试就地执行操作(修改自我)[...]”。

标签: python operators containers


【解决方案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 上测试)

    【讨论】:

      猜你喜欢
      • 2014-04-18
      • 1970-01-01
      • 2017-11-24
      • 2021-08-26
      • 1970-01-01
      • 2021-02-16
      • 2016-08-17
      • 2016-11-02
      • 2011-04-26
      相关资源
      最近更新 更多