Проблема с расширением Python
Я столкнулся с чем-то интересным о расширенном назначении python +=
кажется, что автоматическое преобразование типа данных не всегда выполняется для a += b
, если a является "более простым" типом данных, а a = a + b
работает всегда
случаи, когда выполняется преобразование
a = 1
b = 1j
a = 1
b = 0.5
случай, когда преобразование не выполняется
from numpy import array
a = array([0, 0 ,0])
b = array([0, 0, 1j])
после a += b
, a
остается целочисленной матрицей, а не сложной матрицей
Я привык думать, что a += b
совпадает с a = a + b
, какова разница между ними в основной реализации?
Ответы
Ответ 1
Для оператора +
Python определяет три специальных метода, которые может реализовать объект:
-
__add__
: добавляет два элемента (оператор +
). Когда вы выполняете a + b
, метод __add__
a
вызывается с b
в качестве аргумента.
-
__radd__
: отражение добавить; для a + b
метод __radd__
b
вызывается с a
как экземпляр. Это используется только тогда, когда a
не знает, как сделать добавление, и оба объекта являются разными типами.
-
__iadd__
: добавление на месте; используется для a += b
, где результат присваивается левой переменной. Это предоставляется отдельно, потому что можно было бы реализовать его более эффективным образом. Например, если a
- это список, то a += b
совпадает с a.extend(b)
. Однако в случае c = a + b
вам нужно сделать копию a
, прежде чем расширять ее, так как a
не будет изменяться в этом случае. Обратите внимание: если вы не реализуете __iadd__
, тогда Python просто вызовет __add__
.
Итак, поскольку эти разные операции реализованы с помощью отдельных методов, возможно (но в целом плохая практика) реализовать их, чтобы они делали совершенно разные вещи или, возможно, в этом случае, только несколько разные вещи.
Другие пришли к выводу, что вы используете NumPy и объясняете его поведение. Однако вы спросили об основной реализации. Надеюсь, теперь вы увидите, почему иногда бывает, что a += b
не совпадает с a = a + b
. Кстати, аналогичное трио методов также может быть реализовано для других операций. См. эту страницу для списка всех поддерживаемых методов на месте.
Ответ 2
Если array
- numpy.array
(вы фактически не указываете), то проблема, которая происходит, состоит в том, что эти массивы не могут изменить свой тип. Когда вы создаете массив без спецификатора типа, он угадывает тип. Если вы затем попытаетесь выполнить операцию, тип которой не поддерживается (например, добавление ее к типу с более крупным доменом, например, сложный), numpy знает выполнение вычисления, но он также знает, что результат может быть сохранен только в типе с более крупным доменом. Он жалуется (на моей машине, во всяком случае, в первый раз, когда я выполняю такое задание), что результат не подходит. Когда вы делаете регулярное добавление, в любом случае должен быть создан новый массив, а numpy - правильный тип.
>>> a=numpy.array([1])
>>> a.dtype
dtype('int32')
>>> b=numpy.array([1+1j])
>>> b.dtype
dtype('complex128')
>>> a+b
array([ 2.+1.j])
>>> (a+b).dtype
dtype('complex128')
>>> a+=b
>>> a
array([2])
>>> a.dtype
dtype('int32')
>>>
Ответ 3
Разница между a = a + b
и a += b
заключается в том, что последнее добавление, по возможности, будет выполняться "на месте", что означает изменение объекта a
. Вы можете легко увидеть это со списками.
a = b = [1, 2]
a += [3]
print b # [1, 2, 3]
a = b = [1, 2]
a = a + [3]
print b # [1, 2]
Ответ 4
Ответ Rafe Kettler правильный, но, кажется, вам удалось получить a = [0,0,0] после добавления его в b (согласно вашему сообщению).
Хорошо, если вы используете numpy или scipy (я говорю это, потому что вижу array
и задаюсь вопросом, какой массив создается здесь), тогда это "нормально" и даже должно вызывать предупреждение:
Сложное предупреждение: отличные комплексные значения для реальных отбросов мнимой части