Каждая переменная в Python является ссылкой.
Для списков вы сосредотачиваетесь на результатах метода append()
и упускаете из виду общую картину структур данных Python.Есть и другие методы в списках, и есть свои преимущества и последствия для построения списка.Полезно рассматривать список как вид на другие объекты, указанные в списке.Они не «содержат» ничего, кроме правил и способов доступа к данным, на которые ссылаются объекты внутри них.
Метод list.append(x)
, в частности , эквивалентен l[len(l):]=[list]
Итак:
>>> l1=range(3)
>>> l2=range(20,23)
>>> l3=range(30,33)
>>> l1[len(l1):]=[l2] # equivalent to 'append' for subscriptable sequences
>>> l1[len(l1):]=l3 # same as 'extend'
>>> l1
[0, 1, 2, [20, 21, 22], 30, 31, 32]
>>> len(l1)
7
>>> l1.index(30)
4
>>> l1.index(20)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.index(x): x not in list
>>> 20 in l1
False
>>> 30 in l1
True
Поместив конструктор списка вокруг l2 в l1[len(l1):]=[l2]
или, позвонив l.append(l2)
, вы создаете ссылку, привязанную к l2.Если вы измените l2, ссылки также покажут это изменение.Длина этого списка - один элемент - ссылка на добавленную последовательность.
Без ярлыка конструктора, как в l1[len(l1):]=l3
, вы копируете каждый элемент последовательности.
Если вы используете другие распространенные методы списка, такие как l.index(something)
или in
, вы не найдете элементов внутри ссылок на данные.l.sort()
не будет сортироваться должным образом.Это «мелкие» операции над объектом, и с помощью l1[len(l1):]=[l2]
вы сейчас создаете рекурсивную структуру данных.
Если вы используете l1[len(l1):]=l3
, вы делаете точную (мелкую) копию элементов в l3
.
Это довольно фундаментальные идиомы Python, и большую часть времени они «делают правильные вещи».Однако вы можете получить неожиданные результаты, такие как:
>>> m=[[None]*2]*3
>>> m
[[None, None], [None, None], [None, None]]
>>> m[0][1]=33
>>> m
[[None, 33], [None, 33], [None, 33]] # probably not what was intended...
>>> m[0] is m[1] is m[2] # same object, that's why they all changed
True
Некоторые новички в Python пытаются создать многомерное, выполняя что-то вроде m=[[None]*2]*3
Первая репликация последовательности работает как положено;он создает 2 копии None
.Это вторая проблема: она создает три копии ссылки на первый список.Поэтому ввод m[0][1]=33
изменяет список внутри списка, привязанного к m, а затем все связанные ссылки изменяются, чтобы показать это изменение.
Сравните с:
>>> m=[[None]*2,[None]*2,[None]*2]
>>> m
[[None, None], [None, None], [None, None]]
>>> m[0][1]=33
>>> m
[[None, 33], [None, None], [None, None]]
Вы также можете использовать понимание вложенного списка сделать то же самое так:
>>> m=[[ None for i in range(2)] for j in range(3)]
>>> m
[[None, None], [None, None], [None, None]]
>>> m[0][1]=44
>>> m
[[None, 44], [None, None], [None, None]]
>>> m[0] is m[1] is m[2] # three different lists....
False
Для списков и ссылок у Фредрика Лунда есть этот текст для хорошего вступления.
Что касается ваших конкретных вопросов:
1) В Python Все является меткой или ссылкой на объект.Не существует «оригинала» (концепция C ++) и нет различия между «ссылкой», указателем или фактическими данными (концепция C / Perl)
2) У Фредрика Лунда есть отличная аналогия в отношении ссылок на вопрос, похожий на этот :
Точно так же, как вы получаете имя того кота, которого нашли на крыльце: сам кот (объект) не может сказать вам свое имяи на самом деле это не волнует - так что единственный способ узнать, как он называется, это спросить всех ваших соседей (пространства имен), является ли их кошка (объект) ...
.... ине удивляйтесь, если вы обнаружите, что он известен под многими именами, или вообще без имен!
Вы можете найти этот список с некоторыми усилиями, но почему?Просто назовите это так, как вы назовете - как найденный кот.
3) Верно.