В чем разница в поведении `[]` и `list()'?

print(id([]) == id([]))
# prints 'True'

print(id(list()) == id(list()))
# prints 'False'

x = []
y = []
print(id(x) == id(y))
# prints 'False'

Почему list() ведет себя иначе, чем [] в отношении приведенного выше кода?

Один буквальный, а другой — функция, но они взаимозаменяемы как синтаксический сахар. stackoverflow.com/questions/33716401/…

Rahul 09.04.2019 08:14
Код, который вы добавили в свое редактирование, не делает того, что вы говорите. И [[]] * 5, и [list()] * 5 создают единый список, содержащий 5 одинаковых ссылок на один список, а не 5 ссылок на разные списки. Вы, вероятно, сделали что-то вроде x[0][0] = 'A' вместо x[0] = 'A' в своем реальном тесте.
user2357112 supports Monica 09.04.2019 08:31

Повторное открытие, потому что повторяющиеся ссылки ничего не говорят о поведении id, которое находится в центре внимания этого вопроса.

user2357112 supports Monica 09.04.2019 08:36

Да. Я не проверял это раньше. Так вы говорите, что все списки в [[]] * 5 или [list()] * 5 относятся к одному и тому же списку? @user2357112

Puneet Singh 09.04.2019 08:37

Обратите внимание, что наличие пула объектов для литералов определяется реализацией. PyPy не делает этого трюка.

MisterMiyagi 09.04.2019 08:50
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
5
216
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

id(object) возвращает идентификатор объекта.

Выражение == оценивается как True, если объекты, на которые ссылаются переменные, равны (имеют одинаковое содержимое).

Поэтому, когда вы используете конструктор list() каждый раз, когда создается новый объект, и его идентификатор отличается, поэтому он оценивается как false, даже если новый объект немедленно отбрасывается, он создается сначала, поэтому другой идентификатор.

Напротив, [] является буквальным (более быстрый способ создания объекта) и всегда имеет один и тот же идентификатор, но когда он создает новый объект, новый объект также получает свой новый идентификатор.

TLDR;[] является литералом и, следовательно, имеет фиксированный идентификатор, list() создает новый объект, x=[]y=[] создает новый объект x и y, поэтому идентификаторы x и y не совпадают, list() каждый раз создает новый объект, поэтому отличается идентификатор при каждом звонке.

Также x = [] будет быстрее, чем x = list(), но это просто сноска, и я не могу понять, как сделать ее маленькой и поставить как сноску :)

[] и list() создают новые объекты. [] не копирует существующий список в пустой объект. Этот ответ неверен.
user2357112 supports Monica 09.04.2019 08:26

Вы можете проверить это, используя дизассемблер для просмотра байт-кода, выполненного для [], а затем перейдя в исходный код цикла оценки байт-кода, чтобы увидеть реализацию используемого кода операции BUILD_LIST.

user2357112 supports Monica 09.04.2019 08:28

Хм, я читаю об этом, я поправлю, если я ошибаюсь, что выглядит вероятным, поскольку литералы - это быстрый способ создания объектов, я думаю, что у меня что-то не так.

anand_v.singh 09.04.2019 08:30
Ответ принят как подходящий

В вашем третьем 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 происходит размещение двух списков в разной памяти, что приводит к разным значениям идентификаторов.

Другие вопросы по теме