print(id([]) == id([]))
# prints 'True'
print(id(list()) == id(list()))
# prints 'False'
x = []
y = []
print(id(x) == id(y))
# prints 'False'
Почему list() ведет себя иначе, чем [] в отношении приведенного выше кода?
[[]] * 5, и [list()] * 5 создают единый список, содержащий 5 одинаковых ссылок на один список, а не 5 ссылок на разные списки. Вы, вероятно, сделали что-то вроде x[0][0] = 'A' вместо x[0] = 'A' в своем реальном тесте.
Повторное открытие, потому что повторяющиеся ссылки ничего не говорят о поведении id, которое находится в центре внимания этого вопроса.
Да. Я не проверял это раньше. Так вы говорите, что все списки в [[]] * 5 или [list()] * 5 относятся к одному и тому же списку? @user2357112
Обратите внимание, что наличие пула объектов для литералов определяется реализацией. PyPy не делает этого трюка.






id(object) возвращает идентификатор объекта.
Выражение == оценивается как True, если объекты, на которые ссылаются переменные, равны (имеют одинаковое содержимое).
Поэтому, когда вы используете конструктор list() каждый раз, когда создается новый объект, и его идентификатор отличается, поэтому он оценивается как false, даже если новый объект немедленно отбрасывается, он создается сначала, поэтому другой идентификатор.
Напротив, [] является буквальным (более быстрый способ создания объекта) и всегда имеет один и тот же идентификатор, но когда он создает новый объект, новый объект также получает свой новый идентификатор.
TLDR;[] является литералом и, следовательно, имеет фиксированный идентификатор, list() создает новый объект, x=[]y=[] создает новый объект x и y, поэтому идентификаторы x и y не совпадают, list() каждый раз создает новый объект, поэтому отличается идентификатор при каждом звонке.
Также x = [] будет быстрее, чем x = list(), но это просто сноска, и я не могу понять, как сделать ее маленькой и поставить как сноску :)
[] и list() создают новые объекты. [] не копирует существующий список в пустой объект. Этот ответ неверен.
Вы можете проверить это, используя дизассемблер для просмотра байт-кода, выполненного для [], а затем перейдя в исходный код цикла оценки байт-кода, чтобы увидеть реализацию используемого кода операции BUILD_LIST.
Хм, я читаю об этом, я поправлю, если я ошибаюсь, что выглядит вероятным, поскольку литералы - это быстрый способ создания объектов, я думаю, что у меня что-то не так.
В вашем третьем id сравнении вы сравниваете значения идентификаторов двух объектов с перекрывающимися сроками службы. Это должно вернуть False по контракту функции id. Вы увидите такое же поведение с list().
В обоих ваших первых двух id сравнениях задействованные объекты имеют непересекающиеся времена жизни. Совпадают ли значения идентификаторов объектов с непересекающимися временами жизни — это деталь реализации, и вы не должны полагаться на то, что это так или иначе. Поведение может быть изменено без предварительного уведомления.
В текущем CPython значения идентификатора совпадают с [], потому что [] использует код операции BUILD_LIST, который вызывает функцию C PyList_New, а PyList_New использует свободный список освобожденных структур заголовка списка для ускорения выделения:
PyObject *
PyList_New(Py_ssize_t size)
{
...
if (numfree) {
numfree--;
op = free_list[numfree];
_Py_NewReference((PyObject *)op);
Когда списки освобождаются, буфер, содержащий указатели на элементы, освобождается, но (до максимального размера свободного списка) заголовок, содержащий информацию о таких вещах, как тип объекта, количество ссылок, емкость и т. д. входит в список бесплатных:
static void
list_dealloc(PyListObject *op)
{
...
if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
free_list[numfree++] = op;
else
Py_TYPE(op)->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op)
}
Список, созданный первым [], умирает перед вторым [] выражением, поэтому его заголовок попадает в свободный список, а затем повторно используется вторым []. Значение id основано на адресе этого заголовка, поэтому оба списка имеют одинаковое значение идентификатора.
Напротив, list() проходит через tp_new и tp_init, а listtp_new — это PyType_GenericNew, который не проходит через тот же список свободных мест. PyType_GenericNew происходит размещение двух списков в разной памяти, что приводит к разным значениям идентификаторов.
Один буквальный, а другой — функция, но они взаимозаменяемы как синтаксический сахар. stackoverflow.com/questions/33716401/…