Почему некоторые выражения, ссылающиеся на `x.y `, изменяют `id (x.y )`?

Этот вопрос относится к (как минимум )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

Таким образом, весь вопрос состоит из следующих частей:

  • Какие виды атрибутов могут изменить свою идентичность как побочный эффект выражений, которые не изменяют эти атрибуты?

  • Какие выражения вызывают такие изменения?

  • Каков механизм, вызывающий такие изменения?

  • При каких условиях перерабатываются прошлые личности?

  • Почему первое удостоверение не перерабатывается на неопределенный срок, что позволило бы избежать всех этих осложнений?

  • Что-нибудь из этого задокументировано?

6
задан nisavid 31 March 2018 в 10:47
поделиться