Подтвердить что ты не робот

Есть ли разница между [] и list() при использовании id()?

Может кто-нибудь объяснить следующее?

Почему id одинаковый, но списки разные?

>>> [] is []
False
>>> id([]) == id([])
True

Есть ли разница в создании списка?

>>> id(list()) == id(list())
False
>>> id([]) == id([])
True

Почему это происходит? Я получаю два разных списка. Почему не только один или три или более?

>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868128>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868170>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868128>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868170>
4b9b3361

Ответ 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>

Вы никогда не создаете более двух списков; предыдущий (все еще ссылающийся на _) и текущий. Если вы хотите увидеть больше мест памяти, используйте переменные, чтобы добавить другую ссылку.