这个问题与(至少)CPython 2.7.2 和 3.2.2 相关。
假设我们定义Class
和obj
如下。
class Class(object):
def m(self):
pass
@property
def p(self):
return None
@staticmethod
def s():
pass
obj = Class()
简洁版本
为什么False
每个都输出以下代码print()
?
print(Class.__dict__ is Class.__dict__)
print(Class.__subclasshook__ is Class.__subclasshook__)
print(Class.m is Class.m)
print(obj.__delattr__ is obj.__delattr__)
print(obj.__format__ is obj.__format__)
print(obj.__getattribute__ is obj.__getattribute__)
print(obj.__hash__ is obj.__hash__)
print(obj.__init__ is obj.__init__)
print(obj.__reduce__ is obj.__reduce__)
print(obj.__reduce_ex__ is obj.__reduce_ex__)
print(obj.__repr__ is obj.__repr__)
print(obj.__setattr__ is obj.__setattr__)
print(obj.__sizeof__ is obj.__sizeof__)
print(obj.__str__ is obj.__str__)
print(obj.__subclasshook__ is obj.__subclasshook__)
print(obj.m is obj.m)
(这适用于 Python 2;对于 Python 3,省略print()
for并为、、、、和Class.m
添加类似print()
的 s )obj.__eq__
obj.__ge__
obj.__gt__
obj.__le__
obj.__lt__
obj.__ne__
另一方面,为什么会True
为每个输出以下代码print()
?
print(Class.__class__ is Class.__class__)
print(Class.__delattr__ is Class.__delattr__)
print(Class.__doc__ is Class.__doc__)
print(Class.__format__ is Class.__format__)
print(Class.__getattribute__ is Class.__getattribute__)
print(Class.__hash__ is Class.__hash__)
print(Class.__init__ is Class.__init__)
print(Class.__module__ is Class.__module__)
print(Class.__new__ is Class.__new__)
print(Class.__reduce__ is Class.__reduce__)
print(Class.__reduce_ex__ is Class.__reduce_ex__)
print(Class.__repr__ is Class.__repr__)
print(Class.__setattr__ is Class.__setattr__)
print(Class.__sizeof__ is Class.__sizeof__)
print(Class.__str__ is Class.__str__)
print(Class.__weakref__ is Class.__weakref__)
print(Class.p is Class.p)
print(Class.s is Class.s)
print(obj.__class__ is obj.__class__)
print(obj.__dict__ is obj.__dict__)
print(obj.__doc__ is obj.__doc__)
print(obj.__module__ is obj.__module__)
print(obj.__new__ is obj.__new__)
print(obj.__weakref__ is obj.__weakref__)
print(obj.p is obj.p)
print(obj.s is obj.s)
(这适用于 Python 2;对于 Python 3,为, , , , , 和, and添加类似print()
的 s )Class.__eq__
Class.__ge__
Class.__gt__
Class.__le__
Class.__lt__
Class.__ne__
Class.m
长版
如果我们连续请求id(obj.m)
两次,我们(不出所料)会两次获得相同的对象 ID。
>>> id(obj.m)
139675714789856
>>> id(obj.m)
139675714789856
但是,如果我们请求id(obj.m)
,然后评估一些引用 的表达式obj.m
,然后再次请求id(obj.m)
,我们有时(但并非总是)发现对象 ID 已更改。在它发生变化的情况中,在某些情况下,再次请求id(obj.m)
会导致 ID 变回原始值。在没有变回的情况下,在id(obj.m)
调用之间重复表达式显然会导致 ID 在两个观察值之间交替。
以下是对象 ID 不变的一些示例:
>>> print(obj.m); id(obj.m)
<bound method Class.m of <__main__.Class object at 0x7f08c96058d0>>
139675714789856
>>> obj.m is None; id(obj.m)
False
139675714789856
>>> obj.m.__func__.__name__; id(obj.m)
'm'
139675714789856
>>> obj.m(); id(obj.m)
139675714789856
这是一个对象 ID 更改然后又变回的示例:
>>> obj.m; id(obj.m); id(obj.m)
<bound method Class.m of <__main__.Class object at 0x7f08c96058d0>>
139675715407536
139675714789856
这是一个对象 ID 发生变化,然后不会变回的示例:
>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675715407536
139675715407536
这是相同的示例,操作表达式重复了几次以演示交替行为:
>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675714789856
139675714789856
>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675715407536
139675715407536
>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675714789856
139675714789856
因此,整个问题由以下部分组成:
作为不修改这些属性的表达式的副作用,哪些类型的属性可能会改变它们的身份?
什么样的表达方式会触发这种变化?
导致这种变化的机制是什么?
过去的身份在什么条件下被回收?
为什么不无限期地回收第一个身份,这样可以避免所有这些复杂性?
有这些记录吗?