Немного странно, когда нужны два разных по идентификатору, но одинаковых по значению кортежа, но у меня были законные причины иногда делать подобные странные вещи, поэтому я думаю, что вопрос заслуживает ответа за чистую монету.
Причина, по которой y
дает список из трех ссылок на один и тот же кортеж, заключается в том, что кортеж (None, None)
является константой времени компиляции, поэтому его байт-код представляет собой простой LOAD_CONST
, который выполняется внутри понимания списка и, конечно же, загрузка одной и той же константы три раза просто создает три ссылки на нее, а не три копии.
Чтобы обойти это, нам нужно выражение, значение которого равно (None, None)
, но для которого выражение не является константой времени компиляции. Вызов функции tuple
делает это, по крайней мере в версиях Python, которые я тестировал (3.5.2 и 3.8.1):
[tuple([None, None]) for _ in range(3)]
Честно говоря, я немного удивлен, что x
у него есть три разных копии, и это почти наверняка специфика реализации c, на которую вы не должны полагаться. Но, аналогично, tuple.__new__
не всегда создает новый кортеж; например tuple( (None, None) )
возвращает ссылку на фактический аргумент, а не его копию. Таким образом, не гарантируется, что tuple([None, None])
продолжит производить кортежи с неравными ссылками в других версиях Python.