我以为is操作员检查对象id的相等性.但它似乎并非如此:
>>> class A(object):
... def f(): return 1
... def g(): return 2
...
>>> a = A()
>>> a.f is a.g
False
>>> id(a.f) == id(a.g)
True
Run Code Online (Sandbox Code Playgroud)
Pad*_*ham 15
Python重用相同的内存位置,因为你没有对对象进行其他引用,一旦id(a.f)被评估有更多对该对象的引用,所以它是gc'd然后python可以自由地重用相同的内存位置a.g.如果将方法分配给名称,您将看到不同的行为:
# creates a reference to the method f
In [190]: f = a.f
# creates a reference to the method g
In [191]: g = a.g
# cannot reuse the memory location of f as it is still referenced
In [192]: id(f) == id(g)
Out[192]: False
Run Code Online (Sandbox Code Playgroud)
实际上你真的只需要存储对f的引用来查看与上面相同的行为.
In [201]: f = a.f
In [202]: id(f) == id(a.g)
Out[202]: False
Run Code Online (Sandbox Code Playgroud)
您可以使用sys.getrefcount或查看引用计数gc.gc.get_referrers:
In [2]: import gc
In [3]: f = a.f
In [4]: len(gc.get_referrers(a.g)),len(gc.get_referrers(f))
Out[4]: (0, 1)
In [5]: sys.getrefcount(a.g),sys.getrefcount(f)
Out[5]: (1, 2)
Run Code Online (Sandbox Code Playgroud)
您为ag看到1的唯一原因是因为返回的计数通常比您预期的高一个,因为它包含(临时)引用作为getrefcount()的参数.
它类似于你自己的例子,在评估方法之后,你仍然会引用f,a.grefcount将为0,因此它立即被垃圾收集,python可以自由地使用内存位置进行其他任何操作.
值得注意的是,行为不仅限于方法,而且它只是一个cpython实现细节,而不是你应该依赖的东西:
In [67]: id([]), id([])
Out[67]: (139746946179848, 139746946179848)
In [73]: id(tuple()),id([]),id([])
Out[73]: (139747414818888, 139746946217544, 139746946217544)
In [74]: id([]),id([]),id([])
Out[74]: (139746946182024, 139746946182024, 139746946182024)
In [75]: id([]),id(tuple()),id([])
Out[75]: (139746946186888, 139747414818888, 139746946186888)
In [76]: id(tuple()),id([]),id(tuple())
Out[76]: (139747414818888, 139746946217736, 139747414818888)
Run Code Online (Sandbox Code Playgroud)
a.fPython 方法和正在使用相同的内存a.g位置,它们是**两个具有不重叠生命周期的对象*,因此id为它们返回相同的标识。请参阅下面更详细的解释。
来自is 运算符的文档:
\n\n\n\n\n运算符 is 和 is not 测试对象身份:x is y is true\n 当且仅当 x 和 y 是同一对象时。
\n
从文档中可以看出来自 is id
\n\n\n\n\n返回对象的\xe2\x80\x9cidentity\xe2\x80\x9d。这是一个整数(或 long\n 整数),保证该对象在其生命周期内是唯一且恒定的。具有不重叠生命周期的两个对象可能具有相同的 id() 值。
\n
说明:
\n\nclass.name每当您通过或查找方法时instance.name,都会创建一个新的方法对象。Python使用描述符协议将函数包装在方法对象中。
所以,当你抬头id(a.f)或id(a.g)时,会创建一个新的方法对象。
a.f,会在内存中创建它的副本。该内存位置由以下命令返回id。a.g,会在同一内存地址创建它的副本,您可以使用以下命令检索该副本id再次检索该地址。祝你好运!
\n| 归档时间: |
|
| 查看次数: |
1888 次 |
| 最近记录: |