2013-04-09 44 views
6
def f(x): 
    x=x/5. 
    return x 
def g(x): 
    x/=5. 
    return x 

x_var = np.arange(5,dtype=np.double) 
f(x_var) 
print x_var 
g(x_var) 
print x_var 

Output: 
[ 0. 1. 2. 3. 4.] 
[ 0. 0.2 0.4 0.6 0.8] 

这种行为有点奇怪,我一直认为x/= 5。相当于x = x/5。 。但显然,g(x)函数不会在/ =操作中创建新的引用。任何人都可以为此提供解释吗?numpy自我分裂的意外行为

回答

5

我一直以为x/= 5。相当于X = X/5

是,除非类覆盖__idiv__操作者,像numpy.ndarray一样。 numpy.ndarray将覆盖它以就地修改数组,这很好,因为它避免了在不需要复制时创建数组的新副本。正如你所猜测的那样,它也会覆盖其他运营商的__i*__

+0

感谢您的解释,我找不到可能导致我期待此行为的文档。 – bluecat 2013-04-09 16:44:07

+5

这不是一个numpy问题,它是一个通过引用对象传递的问题。所有'__i * __'的默认实现都是在可能的情况下进行操作,请阅读[docs](http://docs.python.org/reference/datamodel.html#object.__iadd__)。将一个Python列表传递给一个函数def f(a):a * = 3;返回a',它会修改您调用它的原始对象,而不是简单地返回修改后的副本。 – Jaime 2013-04-09 16:52:00

+1

谢谢,这是我正在寻找的文档参考。所以如果可能的话,它应该在原地进行操作。如果__i * __不可用,它将默认为正常的__ * __操作。 – bluecat 2013-04-09 17:03:15

3

Python的就地操作符允许操作修改等式左边的对象,而不是创建一个新对象。你会看到list S和其他内置可变类型相同的行为:

x = [] 
y = x 
x += [1] 
print y # prints [1] because x still refers to the same object as y 
x = x + [2] 
print x # prints [1, 2] for obvious reasons 
print y # prints [1] again because x has been rebound to a new list 
      # while y still refers to the original one 

所以这是预期的行为。

当处理不可变类型时,当然会创建一个新对象,因为现有的对象不能被修改。

0

我一直以为x/= 5。相当于x = x/5。

它不是。当你这样做x=x/5.,你其实引擎盖下方进行独立的操作:

temporary = x/5. 
x = temporary 

而当你使用/=运营商,你是明确要求Python来修改你的对象x到位,而不需要创建临时对象。正如其他答案中提到的那样,/运营商调用您的对象的__div__方法(如果有),而/=调用其方法__idiv__

如果您正在修改的对象很大,则就地修改非常有用:不需要创建一个很大的临时对象。但是,如果你不小心,它会咬你。特别是,有一个功能修改其输入参数而不发出警告通常不是一个好主意......