Python оператор присваивания отличается от не присваивания - PullRequest
12 голосов
/ 27 апреля 2020

Я сталкиваюсь с таким странным поведением, о котором не могу найти объяснения.

MWE:

l = [1]
l += {'a': 2}
l
[1, 'a']
l + {'B': 3}
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: can only concatenate list (not "dict") to list

В основном, когда I += python не вызывает ошибку и добавляет ключ к списку, в то время как когда я вычисляю только +, я получаю ожидаемое TypeError.

Примечание: это Python 3.6.10

Ответы [ 2 ]

12 голосов
/ 27 апреля 2020

l += ... фактически вызывает object.__iadd__(self, other) и изменяет объект in-place, когда l является изменяемым

(см. здесь )


l = [1]
l = l.__iadd__({'a': 2})
l
#[1, 'a']

- это не то же самое, что +, который вызывает object.__add__(self, other)

l + {'B': 3}
TypeError: can only concatenate list (not "dict") to list

Причина (как объясняет @DeepSpace в своем комментарии) заключается в том, что когда вы делаете l + = {'a': 2} обновляет l на месте, тип результата ясен (= тип l). l + {'a': 2} не на месте, поэтому тип получающегося нового объекта неоднозначен. Должен ли это быть тип l или тип {'a': 2}?

0 голосов
/ 08 мая 2020

Так что, как говорят авторы, это не ошибка. Когда вы делаете a += b, это похоже на b, когда вы приходите в дом a и меняете его так, как это нравится a. Что авторы говорят, когда вы делаете a + b, не может быть решено, какой стиль будет приоритетным. и никто не знает, где будет результат a + b, будет go, пока вы его не выполните. Так что вы не можете решить, чей это будет стиль. если это стиль a, то будет [1, 'a'], а если это стиль b, это будет ошибкой. и поэтому не может быть решено, кто получит приоритет . Так что я лично не согласен с этим утверждением. потому что когда вы берете стек вызовов a находится выше, чем b. когда есть выражение типа a + b, вы сначала вызываете a.__add__(self, other), если a.__add__ равно NotImplemented (в данном случае оно реализовано). тогда вы звоните a.__radd__(self, other). что означает вызов other.__add__ в этом случае b.__add__. Я говорю об этом в зависимости от места стека вызовов, и у сообщества python могут быть более важные причины для этого.

...