Этот вопрос относится к (как минимум )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()
для Class.m
и добавьте аналогичные print()
для 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 добавьте аналогичные print()
для Class.__eq__
, Class.__ge__
, Class.__gt__
, Class.__le__
, Class.__lt__
и Class.__ne__
иClass.m
)
. Если мы попросим id(obj.m)
два раза подряд, мы (неудивительно, что )дважды получаем один и тот же идентификатор объекта.
>>> id(obj.m)
139675714789856
>>> id(obj.m)
139675714789856
Однако, если мы запросим id(obj.m)
, а затем оценим некоторые выражения, которые ссылаются на obj.m
, затем снова запросим id(obj.m)
, мы иногда (, но не всегда )обнаружим, что идентификатор объекта изменился. Среди ситуаций, когда он изменяется, в некоторых из них повторный запрос id(obj.m)
приводит к тому, что идентификатор возвращается к исходному значению. В тех случаях, когда он не меняется обратно, повторение выражений между вызовами id(obj.m)
, по-видимому, приводит к тому, что идентификатор чередуется между двумя наблюдаемыми значениями.
Вот несколько примеров, когда идентификатор объекта не меняется:
>>> 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
Вот пример, когда идентификатор объекта изменяется, а затем возвращается обратно:
>>> obj.m; id(obj.m); id(obj.m)
<bound method Class.m of <__main__.Class object at 0x7f08c96058d0>>
139675715407536
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
>>> 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
Таким образом, весь вопрос состоит из следующих частей:
Какие виды атрибутов могут изменить свою идентичность как побочный эффект выражений, которые не изменяют эти атрибуты?
Какие выражения вызывают такие изменения?
Каков механизм, вызывающий такие изменения?
При каких условиях перерабатываются прошлые личности?
Почему первое удостоверение не перерабатывается на неопределенный срок, что позволило бы избежать всех этих осложнений?
Что-нибудь из этого задокументировано?