import numpy as np
def f(x):
x /= 10
data = np.linspace(0, 1, 5)
print data
f(data)
print data
我系统上的输出(debian 8,Python 2.7.9-1,numpy 1:1.8.2-2)
[ 0. 0.25 0.5 0.75 1. ]
[ 0. 0.025 0.05 0.075 0.1 ]
通常,我希望data
将其传递给函数时保持不变,因为它具有自己的独立命名空间。但是,当数据是一个numpy数组时,该函数会data
全局更改。
这是功能,错误还是我可能会遗漏某些东西?使用自定义绘图功能自动缩放数据时,应如何避免这种行为?
更新(有关更多详细信息,请参见Kevin J. Chase的答案)
import numpy as np
def f(x):
print id(x)
x = x/10
print id(x)
data = np.linspace(0, 1, 5)
print id(data)
print data
f(data)
print data
我系统上的输出(debian 8,Python 2.7.9-1,numpy 1:1.8.2-2)
48844592
[ 0. 0.25 0.5 0.75 1. ]
48844592
45972592
[ 0. 0.25 0.5 0.75 1. ]
使用x = x/10
而不是x /= 10
为我解决了问题。
nice和shortx /= 10
语句的行为实际上很大程度上取决于x的类型。如果x是不可变的,它将重新绑定,否则进行变异。
它不等于x = x/10
总是重新绑定。
numpy数组是可变对象。
通常,我希望将数据传递给函数时保持不变,因为它具有自己的独立命名空间。
x
在功能和data
模块级别上,同一对象的两个名称。由于该对象是可变的,因此无论使用哪个名称来引用该对象,对它所做的任何更改都将被“看到”。命名空间无法保护您。
x /= 10
将NumPy数组的每个元素除以10。执行此行后,原始数据消失了。如果要运行f(data)
几次,您会发现每次绘制的内容都接近于0.0。
列表是具有相同效果的更熟悉的示例:
l = list(range(4))
print(l)
# [0, 1, 2, 3]
l += [4]
print(l)
# [0, 1, 2, 3, 4]
为了对这种事情(包括相关问题)有一个很好的概述,我推荐Ned Batchelder的“关于Python名称和值的事实和神话”(PyCon US 2015的26分钟视频)。他的“添加”列表示例开始于大约10分钟。
/
和/=
(以及类似的运算符对)做不同的事情。教程经常声称这两个操作是相同的:
x = x / 10
x /= 10
...但事实并非如此。全部细节可以发现Python语言参考,3.3.7。模拟数值类型。
/
在两个对象之一上调用__truediv__
(或者可能__rtruediv__
是另一天的主题)方法,并将另一个对象作为参数:
# x = x / 10
x = x.__truediv__(10)
通常,这些方法在不更改旧值的情况下返回一些新值。这就是为什么data
未更改x / 10
但被id(x)
更改的原因---x
现在引用了一个新对象,并且不再是的别名data
。
/=
__itruediv__
为“就地”操作调用完全不同的方法:
# x /= 10
x = x.__itruediv__(10)
这些方法通常会修改对象,然后返回self
。这就解释了为什么id(x)
没有改变和为什么data
的内容发生了变化---x
并data
仍是唯一对象。从我上面链接的文档中:
这些方法应尝试就地进行操作(modify
self
)并返回结果(可以是,但不一定是self
)。如果未定义特定方法,则扩展分配将退回到常规方法[含义__add__
和族--- KJC ]。
如果查看不同数据类型的方法,您会发现它们不支持所有这些方法。
dir(0)
表明整数缺少就位方法,这并不奇怪,因为它们是不可变的。
dir([])
仅显示两个就地方法:__iadd__
和__imul__
---您不能从列表中除或减去,但可以就地添加另一个列表,并且可以将其乘以整数。(同样,这些方法可以对参数做任何想做的事情,包括拒绝它们……list.__iadd__
不会取整数,而list.__imul__
会拒绝列表。)
dir(np.linspace(0, 1, 5))
基本上显示了所有的算术,逻辑和按位方法,每种方法都具有常规和就地方法。(可能会缺少一些---我没有全部算出来。)
最后,再次重申,这些对象在调用其方法时所处的命名空间完全没有区别。在Python中,数据没有作用域...如果您有对它的引用,则可以在其上调用方法。(摘自Ned Batchelder的演讲:变量具有范围,但没有类型;数据具有类型,但没有范围。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句