【问题标题】:Adding a string to a list using augmented assignment使用增强赋值将字符串添加到列表
【发布时间】:2022-12-11 10:34:05
【问题描述】:
>>> 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__ 是 inplace __add__,在这种情况下情况并非如此......也许有人可以解释这种行为或点/链接下的理性对此进行一些讨论?我从 Karl 的评论中了解到有人对此表示关注

标签: 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】:

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

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

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

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

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

    大多数其他类型,包括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')。

      【讨论】:

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