В Python (2 и 3). Всякий раз, когда мы используем нарезку списка, он возвращает новый объект, например:
l1 = [1,2,3,4]
print(id(l1))
l2 = l1[:]
print(id(l2))
Вывод
>>> 140344378384464
>>> 140344378387272
Если то же самое повторяется с кортежем, возвращается тот же объект, например:
t1 = (1,2,3,4)
t2 = t1[:]
print(id(t1))
print(id(t2))
Вывод
>>> 140344379214896
>>> 140344379214896
Было бы замечательно, если бы кто-то мог пролить свет на то, почему это происходит, на протяжении всего моего опыта с Python у меня было впечатление, что пустой фрагмент возвращает новый объект.
Насколько я понимаю, он возвращает тот же объект, поскольку кортежи неизменны, и нет смысла создавать его новую копию. Но опять же, это нигде не упоминается в документах.
l2 = tuple(iter(l1))
обходит оптимизациюPyTuple_GetSlice
был задокументирован неточно после просмотра вашего вопроса. Документы теперь исправлены (это была проблема bpo 38557 ).Ответы:
Реализации могут возвращать идентичные экземпляры для неизменяемых типов (в CPython иногда могут появляться похожие оптимизации для строк и целых чисел). Поскольку объект нельзя изменить, в пользовательском коде нет ничего, что могло бы заботиться о том, содержит ли он уникальный экземпляр или просто другую ссылку на существующий экземпляр.
Вы можете найти короткое замыкание в коде C здесь .
Это деталь реализации, обратите внимание, что pypy не делает то же самое.
источник
a->ob_item
, как(*a).ob_item
, например , он получает член , называемыйob_item
от ,PyTupleObject
что указывает на, и + ILOW переходит к началу среза.Это деталь реализации. Поскольку списки изменчивы,
l1[:]
необходимо создать копию, потому что вы не ожидаете, что измененияl2
повлияютl1
.Так как кортеж является неизменным , вы ничего не можете сделать, чтобы
t2
это могло повлиятьt1
каким-либо видимым образом, поэтому компилятор свободен (но не обязателен ) использовать один и тот же объект дляt1
иt1[:]
.источник
В Python 3. *
my_list[:]
это синтаксический сахар дляtype(my_list).__getitem__(mylist, slice_object)
где:slice_object
это объект среза, построенный изmy_list
атрибутов (длины) и выражения[:]
. Объекты, которые ведут себя таким образом, называются подписанными в модели данных Python, см. Здесь . Для списков и кортежей__getitem__
это встроенный метод.В CPython и для списков и кортежей
__getitem__
интерпретируется операция байт-кода,BINARY_SUBSCR
которая реализована для кортежей здесь и для списков здесь .В случае кортежей, ходьба через код , вы увидите , что в этом блоке кода ,
static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item)
возвращает ссылку на тот же ,PyTupleObject
что он получил в качестве входного аргумента, если элемент типаPySlice
и срез имеет значение весь кортеж.Теперь вы изучите код
static PyObject * list_subscript(PyListObject* self, PyObject* item)
и убедитесь, что независимо от среза, всегда возвращается новый объект списка.источник
start:stop
срез встроенного типа, в том числеtup[:]
, не проходитBINARY_SUBSCR
. Однако расширенная нарезкаstart:stop:step
проходит подписку.Не уверен насчет этого, но кажется, что Python предоставляет вам новый указатель на тот же объект, чтобы избежать копирования, так как кортежи идентичны (и поскольку объект является кортежем, он неизменен).
источник