我已经使用numpy
已有一段时间了,但偶然发现了我不完全了解的一件事:
a = np.ones(20)
b = np.zeros(10)
print(id(a)==id(b)) # prints False
print(id(a), id(b)) # prints (4591424976, 4590843504)
print(id(a[0])==id(b[0])) # prints True
print(id(a[0]), id(b[0])) # prints (4588947064, 4588947064)
print(id(a[0])) # 4588947184
print(id(b[0])) # 4588947280
有人可以解释一下最近四个打印语句中观察到的行为吗?另外,我知道id
为您提供了实际上在内存中分配的唯一对象ID的事实,但是每次我运行最后两个打印语句时,我都会得到不同的id
值。这是预期的行为吗?
答案 0 :(得分:5)
简短的答案是,您应该忘记依赖id
来尝试深入了解python的工作原理。其输出受cpython实现细节,窥孔优化和内存重用的影响。 id
通常是红色鲱鱼。对于numpy尤其如此。
在您的特定情况下,只有a
和b
作为python对象存在。当您使用元素a[0]
时,您将实例化一个新的python对象,类型为numpy.float64
(或者取决于系统,numpy.float32
)的标量。这些是新的python对象,因此被赋予了新的id
,除非解释器意识到 ,否则您将尝试使用该对象两次(这可能是中间示例中发生的情况,尽管我确实感到惊讶,两个具有不同值的numpy.float64
对象被赋予相同的id
,但是如果先为专有名称分配a[0]
和b[0]
,那么奇怪的魔术就消失了,因此这可能是由于进行了一些优化)。内存地址也有可能被解释器重用,从而给您id
个以前出现过的地址。
仅查看numpy的id
毫无意义,即使琐碎的视图也是具有新id
的新python对象,即使它们在所有目的和用途上都与原始的一样好>
>>> arr = np.arange(3)
>>> id(arr)
140649669302992
>>> id(arr[...])
140649669667056
这是id
在交互式外壳中重用的示例:
>>> id(np.arange(3))
140649669027120
>>> id(np.arange(3))
140649669028480
>>> id(np.arange(3))
140649669026480
对于numpy数组,肯定没有int
interning这样的东西,因此以上内容仅是由于解释器重用了id
s。 id
返回一个内存地址的事实再次只是一个cpython实现细节。忘记id
。
您可能只想将numpy与numpy.may_share_memory
和numpy.shares_memory
一起使用。
答案 1 :(得分:0)
请务必注意,Python中的所有内容都是对象,甚至是数字和类。 您已获取2个numpy数组对象,每个对象都包含相同的值,即0。 当你说:
print('id of 0 =',id(0))
a = 0
print('id of a =',id(a))
b = a
print('id of b =',id(b))
c = 0.0
print('id of c =',id(c))
得到的答案类似(您的情况不同)
id of 0 = 140472391630016
id of a = 140472391630016
id of b = 140472391630016
id of c = 140472372786520
因此,整数0
具有唯一的ID。整数0
的ID在生存期内保持不变。浮动0.0
和其他对象的情况与此类似。
因此,在您的情况下,a[0]
或b[0]
的对象ID为零将一直保持不变,直到或除非它是有效的,否则因为它们都包含0
作为对象值。
每次在不同的行中打印a[0]
或b[0]
时,都会返回不同的对象标识,因为您在不同的行触发了它,因此生命周期也不同。
您可以尝试:
print(id(a)==id(b))
print(id(a),id(b))
print(id(a[0])==id(b[0]))
print(id(a[0]),id(b[0]))
输出将是:
False
2566443478752 2566448028528
True
2566447961120 2566447961120
请注意,第二行将返回给您2个不同的numpy数组类型对象的标识,因为它们都是不同的列表。