Обработка данных ссылкой или значением в Python

Рассмотрите следующую сессию. Как различия объяснены? Я думал это a += b синтаксический сахар (и таким образом эквивалентный) a = a + b. Очевидно, я неправ.

>>> import numpy as np
>>> a  = np.arange(24.).reshape(4,6)
>>> print a
[[  0.   1.   2.   3.   4.   5.]
 [  6.   7.   8.   9.  10.  11.]
 [ 12.  13.  14.  15.  16.  17.]
 [ 18.  19.  20.  21.  22.  23.]]
>>> for line in a:
...     line += 100
...
>>> print a #a has been changed
[[ 100.  101.  102.  103.  104.  105.]
 [ 106.  107.  108.  109.  110.  111.]
 [ 112.  113.  114.  115.  116.  117.]
 [ 118.  119.  120.  121.  122.  123.]]
>>>
>>> for line in a:
...     line = line + 999
...
>>> print a #a hasn't been changed
[[ 100.  101.  102.  103.  104.  105.]
 [ 106.  107.  108.  109.  110.  111.]
 [ 112.  113.  114.  115.  116.  117.]
 [ 118.  119.  120.  121.  122.  123.]]

Спасибо

8
задан Boris Gorelik 10 August 2010 в 09:07
поделиться

2 ответа

Использование оператора + приводит к вызову специального метода __ add __ , который должен создать новый объект и не должен изменять оригинал.

С другой стороны, использование оператора + = приводит к вызову __ iadd __ , который должен изменить объект, если это возможно, а не создавать новый объект.

__ add __

Эти методы вызываются для реализации бинарных арифметических операций (+, -, *, //,%, divmod (), pow (), **, <<, >>, &, ^, |). Например, чтобы оценить выражение x + y, где x - это экземпляр класса, имеющего метод __add __ (), вызывается x .__ add __ (y).

__ iadd __

Эти методы вызываются для реализации расширенных арифметических присваиваний (+ =, - =, * =, / =, // =,% =, ** =, << =, >> =, & =, ^ =, | =). Эти методы должны попытаться выполнить операцию на месте (изменить себя) и вернуть результат (который может быть, но не обязательно, самим собой).

Конечно, можно реализовать __ add __ и __ iadd __ , чтобы иметь другое поведение, если хотите, но то, что вы наблюдаете, является стандартным и рекомендуемым способом. И, да, это немного удивительно, когда видишь это впервые.

15
ответ дан 5 December 2019 в 07:33
поделиться

Вы не ошиблись, иногда a + = b действительно является синтаксическим сахаром для a = a + b , но иногда это не так, что является одной из наиболее сбивающих с толку функций Python - см. этот аналогичный вопрос для более подробного обсуждения.

Оператор + вызывает специальный метод __ add __ , а оператор + = пытается вызвать на месте ] __ iadd __ специальный метод, но я думаю, что стоит расширить случай, когда __ iadd __ не определен.

Если оператор на месте не определен, например для неизменяемых типов, таких как строки и целые числа, вместо этого вызывается __ add __ . Итак, для этих типов a + = b на самом деле является синтаксическим сахаром для a = a + b . Этот игрушечный класс иллюстрирует эту мысль:

>>> class A(object):
...     def __add__(self, other):
...         print "In __add__ (not __iadd__)"
...         return A()
...
>>> a = A()
>>> a = a + 1
In __add__ (not __iadd__)
>>> a += 1
In __add__ (not __iadd__)

Это поведение, которое вы должны ожидать от любого неизменяемого типа.Хотя это может сбивать с толку, альтернативой было бы запретить + = для неизменяемых типов, что было бы неудачно, поскольку это означало бы, что вы не могли бы использовать его для строк или целых чисел!

В другом примере это приводит к различию между списками и кортежами, оба из которых поддерживают + = , но могут быть изменены только списки:

>>> a = (1, 2)
>>> b = a
>>> b += (3, 4)   # b = b + (3, 4)   (creates new tuple, doesn't modify)
>>> a
(1, 2)

>>> a = [1, 2]
>>> b = a
>>> b += [3, 4]   # calls __iadd___ so modifies b (and so a also)
>>> a
[1, 2, 3, 4]

Конечно, то же самое касается всех остальных в операторы -place, - = , * = , // = , % = и т. д.

7
ответ дан 5 December 2019 в 07:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: