М. Лутц - Изучаем Python (4-е издание)- 2011 (1126907), страница 77
Текст из файла (страница 77)
Синтаксически вложенные объекты внутри реализованы в виде ссылок (то есть в виде указателей) на отдельные участки памятиСсылки и копииВ главе 6 говорилось, что при выполнении операции присваивания всегда сохраняется ссылка на объект, а не копия самого объекта. В большинстве случаев именно это нам и требуется. Однако в процессе выполнения операцийприсваивания может быть создано несколько ссылок на один и тот же объект,поэтому очень важно понимать, что изменения, произведенные в изменяемом304Глава 9.
Кортежи, файлы и все остальноеобъекте с помощью одной ссылки, отразятся и на других ссылках, указывающих на этот же объект. Если такой порядок вещей является нежелательным,необходимо явно сообщить интерпретатору, чтобы он создал копию объекта.Мы изучили это явление в главе 6, но ситуация может обостриться, когдав игру вступят крупные объекты. Например, в следующем примере создаетсясписок, который присваивается переменной X, затем создается другой список,включающий ссылку на список X, который присваивается переменной L. Далеесоздается словарь D, который содержит еще одну ссылку на список X:>>> X = [1, 2, 3]>>> L = [‘a’, X, ‘b’]>>> D = {‘x’:X, ‘y’:2}# Встроенная ссылка на объект XВ этот момент в программе появляется три ссылки на список, который был создан первым: из переменной X, из элемента списка, соответствующего переменной L, и из элемента словаря, соответствующего переменной D.
Эта ситуацияизображена на рис. 9.2.ИменаОбъектыLXD1?3Рис. 9.2. Разделяемые ссылки на объект: поскольку переменная X, элементсписка L и элемент словаря D ссылаются на один и тот же список, то изменения, произведенные с помощью X, отразятся также на L и DТак как списки относятся к категории изменяемых объектов, изменения в объекте списка, произведенные с помощью любой из трех ссылок, также отразятсяна других двух ссылках:>>> X[1] = ‘surprise’# Изменяет все три ссылки!>>> L[‘a’, [1, ‘surprise’, 3], ‘b’]>>> D{‘x’: [1, ‘surprise’, 3], ‘y’: 2}Ссылки – это более высокоуровневый аналог указателей в других языках программирования. И хотя вы не можете извлечь непосредственное значение самойссылки, тем не менее одну и ту же ссылку можно сохранить более чем в одномместе (в переменных, в списках и так далее).
Это полезная особенность – выможете передавать крупные объекты между компонентами программы без выполнения дорогостоящей операции копирования. Однако, когда действительнонеобходимо создать копию объекта, вы можете запросить их:305Ссылки и копии•• Выражение извлечения среза с пустыми пределами (L[:]) создает копию последовательности.•• Метод словарей и множеств copy создает копию словаря (D.copy()).•• Некоторые встроенные функции, такие как list, создают копию списка(list(L)).•• Модуль copy, входящий в состав стандартной библиотеки, создает полныекопии объектов.Например, предположим, что у нас имеются список и словарь, и для нас нежелательно изменение их значений посредством других переменных:>>> L = [1,2,3]>>> D = {‘a’:1, ‘b’:2}Чтобы предотвратить такую возможность, достаточно связать с другими переменными копии объектов вместо того, чтобы связать с ними сами объекты:>>> A = L[:]>>> B = D.copy()# Вместо A = L (или list(L))# Вместо B = D (то же относится и к множествам)В этом случае изменения, произведенные с помощью других переменных, повлияют на копии, а не на оригиналы:>>> A[1] = ‘Ni’>>> B[‘c’] = ‘spam’>>>>>> L, D([1, 2, 3], {‘a’: 1, ‘b’: 2})>>> A, B([1, ‘Ni’, 3], {‘a’: 1, ‘c’: ‘spam’, ‘b’: 2})Если вернуться к первоначальному примеру, то избежать побочных эффектов,связанных со ссылками, можно, использовав выражение извлечения среза изоригинального списка:>>> X = [1, 2, 3]>>> L = [‘a’, X[:], ‘b’]>>> D = {‘x’:X[:], ‘y’:2}# Встроенные копии объекта XЭто меняет картину, представленную на рис. 9.2 – L и D теперь ссылаются надругие списки, отличные от X.
Теперь изменения, выполненные с помощью переменной X, отразятся только на самой переменной X, но не на L и D; точно также изменения в L или D никак не будут воздействовать на X.Одно замечание по поводу копий: выражение извлечения среза с пустыми значениями пределов и метод словаря copy создают поверхностные копии – тоесть они не копируют вложенные структуры данных, даже если таковые присутствуют. Если необходима полная копия структуры произвольной глубинывложенности, следует использовать стандартный модуль copy: добавьте инструкцию import copy и вставьте выражение X = copy.deepcopy(Y), которое создастполную копию объекта Y со сколь угодно большой глубиной вложенности.
Этафункция выполняет рекурсивный обход объектов и копирует все составныечасти. Однако такой подход используется намного реже (потому что для этогоприходится писать дополнительный программный код). Обычно ссылки – этоименно то, что нам требуется, в противном случае чаще всего применяются такие способы копирования, как операция извлечения среза и метод copy.306Глава 9. Кортежи, файлы и все остальноеСравнивание, равенство и истинаЛюбые объекты языка Python поддерживают операции сравнения: проверкана равенство, относительная величина и так далее.
Операции сравнения в языке Python всегда проверяют все части составных объектов, пока результат нестанет определенным. В действительности, при сравнивании вложенных объектов интерпретатор ����������������������������������������������������Python����������������������������������������������всегда автоматически выполняет обход структуры данных, чтобы применить операции сравнения рекурсивно, слева направои настолько глубоко, насколько это необходимо. Первое найденное различиеопределяет результат сравнения.Например, при сравнении списков автоматически сравниваются все их компоненты:>>> L1>>> L2>>> L1(True,= [1, (‘a’, 3)] # Разные объекты с одинаковыми значениями= [1, (‘a’, 3)]== L2, L1 is L2 # Равны? Это один и тот же объект?False)В данном случае L1 и L2 ссылаются на совершенно разные списки, но с одинаковым содержимым.
Из-за природы ссылок в языке Python (рассматривалисьв главе 6) существует два способа проверки на равенство:•• Оператор == проверяет равенство значений. Интерпретатор выполняетпроверку на равенство, рекурсивно сравнивая все вложенные объекты.•• Оператор is проверяет идентичность объектов. Интерпретатор проверяет,являются ли сравниваемые объекты одним и тем же объектом (то есть расположены ли они по одному и тому же адресу в памяти).В предыдущем примере L1 и L2 прошли проверку == на равенство (они равны,потому что все их компоненты равны), но не прошли проверку is на идентичность (они ссылаются на разные объекты и соответственно, на разные областипамяти).
Однако обратите внимание, что происходит при сравнивании двухкоротких строк:>>> S1>>> S2>>> S1(True,= ‘spam’= ‘spam’== S2, S1 is S2True)Здесь у нас так же имеется два различных объекта с одинаковыми значениями:оператор == должен вернуть истину, а оператор is – ложь. Но так как интерпретатор с целью оптимизации кэширует и повторно использует короткие строки,в действительности в обе переменные, S1 и S2, записывается ссылка на одну туже строку ‘spam’ в памяти, поэтому оператор is проверки идентичности возвращает истину. Чтобы получить нормальное поведение, потребуется использовать более длинные строки:>>> S1>>> S2>>> S1(True,= ‘a longer string’= ‘a longer string’== S2, S1 is S2False)Разумеется, так как строки являются неизменяемыми, использование механизма кэширования объектов не оказывает отрицательного влияния на программный код – строки нельзя изменить непосредственно, независимо от того,Сравнивание, равенство и истина307сколько переменных ссылаются на них.
Если результат проверки на идентичность кажется вам обескураживающим, вернитесь к главе 6, чтобы освежитьв памяти концепцию ссылок на объекты.Как правило, оператор == – это именно то, что требуется в большинстве случаевпроверки равенства; оператор is предназначен для особых случаев. Мы рассмотрим случаи использования этих операторов далее в книге.Операторы отношений к вложенным структурам также применяются рекурсивно:>>> L1 = [1, (‘a’, 3)]>>> L2 = [1, (‘a’, 2)]>>> L1 < L2, L1 == L2, L1 > L2 # Меньше, равно, больше: кортеж результатов(False, False, True)Здесь L1 больше, чем L2, потому что вложенное число 3 больше, чем 2.