Python дополненная проблема назначения - PullRequest
15 голосов
/ 08 декабря 2010

Я столкнулся с чем-то интересным в дополнении 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, в чем их отличие в базовой реализации?

Ответы [ 4 ]

15 голосов
/ 08 декабря 2010

Для оператора + 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.Кстати, аналогичное трио методов также может быть реализовано для других операций.См. на этой странице для получения списка всех поддерживаемых методов на месте.

8 голосов
/ 08 декабря 2010

Если 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')
>>> 
1 голос
/ 08 декабря 2010

Разница между 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]
0 голосов
/ 08 декабря 2010

Rafe Kettler ответ правильный, но, кажется, вам удалось получить a = [0,0,0] после добавления его в b (согласно вашему сообщению).

Хорошо, если вы используете numpy или scipy (я говорю это, потому что вижу array и задаюсь вопросом, какой массив здесь создается), тогда это "нормально", и даже должно появиться предупреждение:

ComplexWarning: приведение комплексных значений к реальным отбрасывает мнимую часть

...