Ответ 1
Вы использовали id()
неправильно. id([])
принимает идентификатор памяти объекта, который немедленно отбрасывается. В конце концов, ничто не ссылается на него больше, как только id()
делается с ним. Поэтому в следующий раз, когда вы используете id([])
, Python видит возможность повторно использовать память, и вот, эти адреса действительно одинаковы.
Однако это детализация реализации, на которую нельзя положиться, и она не всегда сможет повторно использовать адрес памяти.
Обратите внимание, что значения id()
уникальны только для времени жизни объекта, см. документацию :
Это целое число, гарантируемое быть уникальным и постоянным для этого объекта в течение его жизни. Два объекта с неперекрывающимся временем жизни могут иметь одинаковое значение
id()
.
(Смелый акцент мой).
То, что id(list())
не может повторно использовать расположение памяти, вероятно, связано с дополнительными мучениями кучи, вызванными нажатием текущего кадра в стеке, чтобы вызвать функцию, а затем снова выталкивать его при возврате вызова list()
.
Оба []
и list()
создают новый пустой объект списка; но вам сначала нужно создать ссылки на эти отдельные списки (здесь a
и b
):
>>> a, b = [], []
>>> a is b
False
>>> id(a) == id(b)
False
>>> a, b = list(), list()
>>> a is b
False
>>> id(a) == id(b)
False
То же самое происходит, если вы использовали [].__repr__
. Интерактивный интерпретатор Python имеет специальное глобальное имя _
, которое вы можете использовать для ссылки на последний полученный результат:
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x10e011608>
>>> _
<method-wrapper '__repr__' of list object at 0x10e011608>
Это создает дополнительную ссылку, поэтому метод __repr__
и, по расширению, пустой список, который вы создали для него, по-прежнему считаются активными. Местоположение памяти не освобождено и недоступно для следующего созданного вами списка.
Но выполнение [].__repr__
снова, Python теперь привязывает _
к этому новому объекту метода. Внезапно предыдущий метод __repr__
больше не ссылается ни на что и может быть освобожден, а также объект списка.
В третий раз, когда вы выполняете [].__repr__
, первое место памяти снова доступно для повторного использования, поэтому Python делает именно это:
>>> [].__repr__ # create a new method
<method-wrapper '__repr__' of list object at 0x10e00cb08>
>>> _ # now _ points to the new method
<method-wrapper '__repr__' of list object at 0x10e00cb08>
>>> [].__repr__ # so the old address can be reused
<method-wrapper '__repr__' of list object at 0x10e011608>
Вы никогда не создаете более двух списков; предыдущий (все еще ссылающийся на _
) и текущий. Если вы хотите увидеть больше мест памяти, используйте переменные, чтобы добавить другую ссылку.