【问题标题】:Adding a string to a list using augmented assignment使用扩充赋值将字符串添加到列表
【发布时间】:2012-01-09 12:04:07
【问题描述】:
>>> b = []
>>> c = '1234'
>>> b += c
>>> b
['1', '2', '3', '4']
>>> 

这里发生了什么?这应该行不通,对吧?还是我遗漏了一些明显的东西?

>>> b = []
>>> c = '1234'
>>> b + c
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    b + c
TypeError: can only concatenate list (not "str") to list
>>> 

那么a += b 并不总是等同于a = a + b?

【问题讨论】:

  • 这种行为是否仍然存在于 Python 3.x 中?我总是觉得令人恼火的是,标准库类型违反了 a += b a = a + b 的一般合同(不影响对原始 a 值的任何其他引用)。
  • @Karl Knechtel:不幸的是,它仍然存在于 Python 3.2.1 中。
  • 我在 python 3.2 中检查它,是的。我在查看产生错误结果的初学者代码时发现了这个问题。我在Learning Python 中找不到对这种特定行为的任何引用。我检查了 PEP203,它说使用了__iadd__,但他们也说__iadd__ 是就地__add__,在这种情况下并非如此......也许有人可以解释这种行为或点/链接下的理性对此进行一些讨论?我从卡尔的评论中了解到有人对此表示关注

标签: python string list augmented-assignment


【解决方案1】:

字符串是可迭代的:元素是字符串的字符。当您将可迭代对象添加到列表时,可迭代对象的 元素 会附加到列表中。

以下任何一项都可以满足您的期望(即附加字符串,而不是使用字符串的字符扩展列表):

b += [c]

或

b.append(c)

【讨论】:

    【解决方案2】:

    += 运算符扩展一个列表而不是附加到它:

    >>> b = []
    >>> c = "1234"
    >>> b.append(c)
    >>> b
    ['1234']
    >>> b.extend(c)
    >>> b
    ['1234', '1', '2', '3', '4']
    >>> b += c
    >>> b
    ['1234', '1', '2', '3', '4', '1', '2', '3', '4']
    >>> b += [c]
    >>> b
    ['1234', '1', '2', '3', '4', '1', '2', '3', '4', '1234']
    

    【讨论】:

    • 您知道关于这些运算符(+、+=)对可迭代/序列/...的影响的文档来源吗?
    • @moooeeeep - 在the table in the docs - 你还可以看到它在实际源代码中是如何发生的。
    【解决方案3】:

    这不是对原始问题(我认为已经得到充分回答)的回答,而是对 cme​​ts 中关于增强赋值语义(+= 和类似操作)提出的众多问题的回答。

    简而言之:对于可变类型和不可变类型,增强赋值的工作方式不同。

    str、tuple 和数字类型等是不可变的。元组的内容一旦创建就无法更改,因此您会得到以下行为:

    >>> a = (1, 2)
    >>> b = a
    >>> a += (3, 4)
    >>> a
    (1, 2, 3, 4)
    >>> b
    (1, 2)
    

    str 具有相同的语义。基本上,如果a 是不可变的,则a += b 等价于a = a + b。

    大多数其他类型,包括list,都是可变的。列表的内容可以就地改变,而增强赋值正是这样做的。因此:

    >>> a = [1, 2]
    >>> b = a
    >>> a += [3, 4]
    >>> a
    [1, 2, 3, 4]
    >>> b
    [1, 2, 3, 4]
    

    如果将第三行替换为a = a + [3, 4],则会创建一个新列表,而b 将是[1, 2]。

    对于用户定义的类,语义取决于它的实现方式,但这是根据 PEP 203 应该如何完成的。

    【讨论】:

    • 这是一个非常好的观察结果。 a 和 b 共享相同的内存地址,直到在赋值运算符的左侧评估 a?你能把它包括进去吗?
    【解决方案4】:

    字符串是一个字符序列。列表操作+= 采用任意序列并将序列的每个元素附加到列表中。

    (实际上+= 接受任何可迭代的。)

    【讨论】:

    • + 是不同于 += 的运算符。
    • 我知道,它被称为增强分配,它被定义为等价于 a = a + b(参见 PEP203)。严格地采用这个定义会使我产生错误的期望。这让我感到惊讶(可能我从来不敢在我的 python 代码中的字符串中添加一个列表,所以我以前从来没有遇到过这种情况)。不应该是In the face of ambiguity, refuse the temptation to guess ?.
    • 在 PEP-203 中没有任何地方声称 a += b 等同于 a = a + b。
    【解决方案5】:

    += 是扩展的语法糖,但 + 只是列表连接。如果您扩展,您将遍历参数,在本例中是一个字符串。但是您不能将字符串连接到列表,因此 + 失败。

    【讨论】:

      【解决方案6】:

      你期待什么?如果你想添加 c 作为字符串,你必须这样做:

      b.append(c)
      

      干杯!

      【讨论】:

      • 但正如 Tim 上面解释的那样,+= 的行为与 + 不同
      • 请看蒂姆帖子的评论。
      【解决方案7】:

      本质上,列表中的 += 运算符将检索 c 的迭代器,这将按顺序生成各个字符。如果您打算将实际字符串添加到列表中,产生结果 ['1234'],则可以使用 b.append('1234') 代替。

      【讨论】:

        猜你喜欢
        • 2022-12-11
        • 1970-01-01
        • 2011-12-15
        • 2011-06-16
        • 1970-01-01
        • 2017-10-09
        • 2011-09-10
        • 2018-08-12
        • 2014-07-05
        相关资源
        最近更新 更多