Мы знаем, tuple
s не поддерживают назначение элементов, но мы можем выполнить inplace add
с кортежами, однако этот создает новый объект , так как кортежи являются неизменяемыми. например:
>>> t1 = (1, 2)
>>> id(t1)
154311048
>>> t1 += (3, 4)
>>> t1
(1, 2, 3, 4)
>>> id(t1)
157955320
Это все хорошо. С другой стороны, list
являются изменяемыми и не создают новые объекты при выполнении добавления на месте.
Теперь у меня сложилось впечатление, что добавление на месте в python было реализовано с помощью __iadd__
magi c, поэтому:
>>> l1 = [1,2,3]
>>> l1 += [4, 5]
# is same as
>>> l1 = l1.__iadd__([4,5]) # 1
# but, again for lists, this is also same as, simply
>>> l1.__iadd__([4,5]) # 2
Я предполагаю, что, поскольку операция на месте не гарантируется для неизменяемых объектов, python присваивает l1.__iadd__([4,5])
l1
, иначе для списков, просто вызывая l1.__iadd__([4,5])
без присвоение его обратно l1
приведет к изменению l1
на месте.
Итак, учитывая это, я предположил, что кортежи могут работать следующим образом, то есть
>>> t1 = t1.__iadd__((3,4))
Но,
Traceback (most recent call last):
File "<ipython-input-12-e8ed2ace9f7f>", line 1, in <module>
t1.__iadd__((1,2))
AttributeError: 'tuple' object has no attribute '__iadd__'
Действительно, '__iadd__' in dir(tuple)
оценивается как False
, Тогда я подумал, может быть, внутренне, Python составляет список из кортежей, выполняет __iadd__
и преобразует результат обратно в tuple
(я не знаю, почему кто-то это сделал! Более того, это не будет объясните преимущества производительности для кортежей над списком) или для неизменяемых объектов, __iadd__
может просто вернуться к __add__
и вернуть значение, но после выполнения dis
:
>>> from dis import dis
>>> dis('t1 += (3, 4)')
1 0 LOAD_NAME 0 (t1)
2 LOAD_CONST 0 ((3, 4))
4 INPLACE_ADD
6 STORE_NAME 0 (t1)
8 LOAD_CONST 1 (None)
10 RETURN_VALUE
Но байт-код имеет инструкция INPLACE_ADD
! Для списка это выглядит так:
>>> dis('l1 += [1,2]')
1 0 LOAD_NAME 0 (l1)
2 LOAD_CONST 0 (1)
4 LOAD_CONST 1 (2)
6 BUILD_LIST 2
8 INPLACE_ADD
10 STORE_NAME 0 (l1)
12 LOAD_CONST 2 (None)
14 RETURN_VALUE
Кроме того, в случае list
есть дополнительная инструкция BUILD_LIST
, поэтому tuples
также не создает список!
Как видите, меня это очень смущает. Может кто-нибудь объяснить, что происходит, как это работает?