通过引用或python中的值处理数据

Bor*_*lik 8 python syntax numpy syntactic-sugar

考虑以下会话.如何解释差异?我认为这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.]]
Run Code Online (Sandbox Code Playgroud)

谢谢

Mar*_*ers 15

使用+运算符会调用特殊方法__add__,该方法应创建新对象,不应修改原始对象.

另一方面,使用+=运算符会导致调用,__iadd__如果可能,应该修改对象而不是创建新对象.

__add__

调用这些方法来实现二进制算术运算(+, - ,*,//,%,divmod(),pow(),**,<<,>>,&,^,|).例如,要计算表达式x + y,其中x是具有__add __()方法的类的实例,则调用x .__ add __(y).

__iadd__

调用这些方法来实现增强算术赋值(+ =, - =,*=,/ =,// =,%=,**=,<< =,>> =,&=,^ =,| = ).这些方法应该尝试就地执行操作(修改self)并返回结果(可能是,但不一定是self).

当然,如果你愿意,可以实现__add____iadd__有其他一些行为,但你观察到的是标准和推荐的方式.而且,是的,第一次看到它时有点令人惊讶.


Sco*_*ths 7

你没有错,有时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__)
Run Code Online (Sandbox Code Playgroud)

这是您应该从任何不可变类型中获得的行为.虽然这可能令人困惑,但另一种选择是禁止+=使用不可变类型,这将是不幸的,因为这意味着你不能在字符串或整数上使用它!

再举一个例子,这会导致列表和元组之间的差异,这两者都支持+=,但只能修改列表:

>>> 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]
Run Code Online (Sandbox Code Playgroud)

当然,这同样适用于所有其他就地运营商-=,*=,//=,%=,等.