代码之家  ›  专栏  ›  技术社区  ›  Boris Gorelik

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

  •  8
  • Boris Gorelik  · 技术社区  · 14 年前

    考虑下一节课。这些差异是如何解释的?我想 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.]]
    

    谢谢你

    2 回复  |  直到 14 年前
        1
  •  15
  •   Mark Byers    14 年前

    使用 + 运算符导致调用特殊方法 __add__ 它应该创建一个新对象,而不应该修改原始对象。

    另一方面,使用 += 接线员呼叫 __iadd__ 如果可能,它应该修改对象,而不是创建一个新对象。

    阿萨德

    调用这些方法来实现二进制算术运算(+、-、*、/、%、divmod()、pow()、**、<<、>、&、^、)。例如,要计算表达式x+y,其中x是一个类的实例,该类有一个uuAdd_uu()方法,则调用x。“uuuAdd”(y)。

    阿伊达德

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

    当然可以实现 阿萨德 阿伊达德 如果你愿意的话,你可以有其他的行为,但是你所观察到的是标准的和推荐的方式。而且,是的,你第一次看到它时有点惊讶。

        2
  •  7
  •   Community CDub    8 年前

    你不是错的,有时候 a += b 真的是句法上的糖分 a = a + b 但是有时它不是,这是Python更令人困惑的特性之一-请参见 this similar question 更多讨论。

    这个 + 运算符调用特殊方法 __add__ += 操作人员 试图 就地呼叫 __iadd__ 特殊的方法,但我认为有必要对 阿伊达德 未定义。

    如果未定义就地运算符,例如对于不可变类型(如字符串和整数),则 阿萨德 改为调用。所以对于这些类型 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]
    

    当然,其他所有就地操作人员也是如此, -= , *= , //= , %= 等。