Я думал, что оператор 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
Я думал, что оператор 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
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
На самом деле вам действительно нужно хранить ссылку на f, чтобы увидеть то же поведение, что и выше.
In [201]: f = a.f
In [202]: id(f) == id(a.g)
Out[202]: False
Вы можете увидеть количество ссылок с 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)
Единственная причина, по которой вы видите 1 для a.g, заключается в том, что возвращенный счет обычно выше, чем вы могли ожидать, потому что он включает (временную) ссылку в качестве аргумента для getrefcount().
Это аналогично вашему собственному примеру, после вычисления метода вы все равно будете иметь ссылку на f, при этом a.g refcount будет равен 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)
Одинаковое расположение памяти используется python для методов a.f и a.g, которые представляют собой ** два объекта с неперекрывающимися сроками жизни *, поэтому id возвращает одинаковое имя для обоих из них, см. более подробные объяснения ниже.
Из документации для находится оператор:
Операторы являются и не проверяются для идентичности объекта: x is y истинно тогда и только тогда, когда x и y являются одним и тем же объектом.
Из документации для id
Верните "идентификатор" объекта. Это целое число (или длинное целое), который гарантированно будет уникальным и постоянным для этого объекта в течение его жизни. Два объекта с неперекрывающимися сроками службы могут имеют одинаковое значение id().
Разъяснения:
Всякий раз, когда вы просматриваете метод с помощью class.name или instance.name, объект метода создается a-new. Python использует протокол дескриптора, чтобы каждый раз обматывать функцию в объекте метода.
Итак, при поиске id(a.f) или id(a.g) создается новый объект метода.
a.f, его копия создается в памяти. Эта ячейка памяти возвращается ida.g его копия создается в том же адресе памяти, который вы снова получаете с помощью idХороший недостаток!
a.f и a.g - разные объекты.
оператор возвращает true только тогда, когда они являются одним объектом.
но два объекта с неперекрывающимися временами жизни могут иметь одинаковое значение id().
обратитесь здесь для оператора id
Оператор is проверяет идентификатор объекта не значение, и в этом случае у вас есть две отдельные функции (объект), поэтому они имеют различную идентификацию.
И о следующей части:
>>> id(a.f) == id(a.g)
True
Так как python создает объекты во время выполнения, первый раз, когда python пытается получить идентификатор a.f, a.g не определен и основан на викторине python Два объекта с неперекрывающимися времена жизни могут иметь одинаковое значение id(). SO в этом случае объекты a.f и a.g, которые имеют неперекрывающиеся времена жизни, имеют равный id.
Верните "идентификатор" объекта. Это целое число (или длинное целое), который гарантированно будет уникальным и постоянным для этого объекта в течение его жизни. Два объекта с неперекрывающимися временами жизни могут имеют одинаковое значение id().
Несколько дополнительных заметок о is:
Как я уже говорил в вышеупомянутых строках, оператор будет проверять идентичность объектов, а объект в python будет создан во время выполнения. Но это не верно для некоторых небольших типов, таких как целые числа и строки, потому что ваши - это однотонные объекты, а не объекты python. Следовательно, он будет сразу расположен в памяти, например, типа C.
Для лучшей демонстрации вы можете увидеть следующие примеры:
>>> 100 is 10*10
True
>>>
>>> 1000 is 10*100
False
>>>
И для строк:
>>> 'aaaa'*5 is 'a'*20
True
>>> 'aaaa'*50 is 'a'*200
False