Лутц М. - Изучаем Python (1077325), страница 39
Текст из файла (страница 39)
А пока просто держите в уме, что объекты, допускающие изменения в них самих (то есть изменяемые объекты), всегда подвержены описанным эффектам. В число таких объектов в языке РуС]зоп попадают списки, словари и некоторые объекты, объявленные с помощью инструкции с1аээ. Если такое поведение является нежелательным, вы можете просто копировать объекты. Разделяемые ссылки и равенство В интересах полноты обсуждения должен заметить, что возможность сборки мусора, описанная ранее в этой главе, может оказаться более принципиальным понятием, чем литералы для объектов некоторых типов. Рассмотрим следующие инструкции: »>х=42 »> х = 'аягоЬЬегу' № Обьект 42 теперь уничтожено Так как интерпретатор РуС]зоп кэширует и повторно использует малые целые числа и небольшие строки, о чем уже упоминалось ранее, объект 42 скорее всего не будет уничтожен. Он, скорее всего, останется в системной таблице для повторного использования, когда вы вновь сгенерируете число 42 в программном коде.
Однако большинство объектов уничтожаются немедленно, как только будет потеряна последняя ссылка, особенно те, к которым применение механизма кэширования не имеет смысла, Например, согласно модели ссылок в языке РуФ]топ, существует два разных способа выполнить проверку равенства, Давайте создадим раз- деляемую ссылку для демонстрации: »>1=11, 2, 3] »> И = >» С == И Тгое »> С1аИ Тгое № И и 1 - ссылки на один и тот же обьект № Одно и то же значение № Один и тот же обьект Первый способ, основанный на использовании оператора ==, проверяет, равны ли значения объектов. В языке практически всегда используется именно этот способ.
Второй способ, основанный на использовании оператора ]а, проверяет идентичность объектов. Он возвращает значение Тгое, только если оба имени ссылаются на один и тот же объект, вследствие этого он является более строгой формой проверки равенства. На самом деле оператор 1э просто сравнивает указатели, которые реализуют ссылки, и тем самым может использоваться для выявления разделяемых ссылок в программном коде. Он возвращает значение Ра1эе, даже если имена ссылаются на эквивалентные, но разные объекты, как, например, в следующем случае, когда выполняются два различных литеральных выражения: 176 в Но разные обьекты Посмотрите, что происходит, если те же самые действия выполняются над малыми целыми числами: а долине получиться дза разных обьекта В этом примере переменные Х и У должны быть равны (==, одно и то же значение), но не эквивалентны (18, один и тот же объект), потому что было выполнено два разных литеральных выражения.
Однако из-за того что малые целые числа и строки кэшируются и используются повторно, оператор 18 сообщает, что переменные ссылаются на один и тот же объект. Фактически, если вы действительно хотите взглянуть на работу внутренних механизмов, вы всегда можете запросить у интерпретатора количество ссылок на объект: функция цет гЕТсоопс из стандартного модуля эуэ возвращает значение поля счетчика ссылок в объекте.
Когда я, например, запросил количество ссылок на целочисленный объект 1 в среде разработки 1РЬЕ, я получил число 887 (большая часть ссылок была создана системным программным кодом самой ПН Е, а не мною): »> 1арог1 зуз »> ауз.де1гвтсооп1(1) а 837 указателей на этот участок памяти 837 Такое кэширование объектов и повторное их использование будет малоприменимо к вашему программному коду (если вы не используете оператор тз!).
Так как числа и строки не могут изменяться, совершенно неважно, сколько ссылок указывает на один и тот же объект. Однако такое поведение наглядно демонстрирует один из реализуемых Ру- 1)топ способов оптимизации, направленной на повышение скорости выполнения. Динамическая типизация повсюду В действительности вам совсем не нужно рисовать схемы с именами, объектами, кружочками и стрелками, чтобы использовать Ру1Ьоп. Однако в самом начале пути такие схемы иногда помогают разобраться в необычных случаях.
Если после передачи изменяемого объекта в другую часть программы он возвращается измененным, значит, вы стали свидетелем того, о чем рассказывалось в этой главе. »>1=[1, »> Н = [1, »> 1 == и Тгов »> 11з И Яа)ве »> Х = 42 >»7=42 »> Х == У Тгов »> Х 1з у Тгов Глаза б. Интерлюдия о динамической типизации 2, 3) 2, 3) В Н и 1 ссылаются на разные обьекты В Одно и то ше значение В Тот ие сзиый объект кэширование в действии' В заключение Более того, если к настоящему моменту динамическая типизация кажется вам немного непонятной, вы, вероятно, захотите устранить это недопонимание в будущем. Поскольку в языке Ру$Ьоп все основано на присваивании и на ссылках, понимание основ этой модели пригодится во многих ситуациях. Как будет показано позже, одна и та же модель используется в операторах присваивания, при передаче аргументов функциям, в переменных цикла аког, при импортировании модулей и т.
д. Но к счастью, в РуСЬоп реализована всего одна модель присваивания! Как только вы разберетесь в динамической типизации, вы обнаружите, что подобные принципы применяются повсюду в этом языке программирования. На практическом уровне наличие динамической типизации означает, что вам придется писать меньше программного кода. Однако не менее важно и то, что динамическая типизация составляет основу полиморфизма — концепции, которая была введена в главе 4 и к которой мы еще вернемся далее в этой книге — в языке РуСЬоп.
Поскольку мы не ограничены применением типов в программном коде на языке РуФпоп, он обладает очень высокой гибкостью. Как будет показано далее, при правильном использовании динамической типизации и полиморфизма можно создавать такой программный код„который автоматически будет адаптироваться под новые требования в ходе развития вашей системы. В заключение В этой главе мы подробно рассмотрели модель динамической типизации в языке РуФпоп, то есть способ, который используется интерпретатором для автоматического хранения информации о типах объектов и избавляет нас от необходимости вставлять код объявлений в наши сценарии.
Попутно мы узнали, как реализована связь между переменными и объектами. Кроме того, мы исследовали понятие сборки мусора, узнали, как разделяемые ссылки на объекты могут оказывать воздействие на несколько переменных и как ссылки влияют на понятие равенства в языке РуФЬоп. Поскольку в языке РуФЬоп имеется всего одна модель присваивания, и она используется повсюду в этом языке, очень важно, чтобы вы разобрались в ней, прежде чем двигаться дальше. Контрольные вопросы к этой главе должны помочь вам повторить некоторые идеи этой главы.
После этого в следующей главе мы возобновим наш обзор объектов, приступив к изучению строк. Закрепление пройденного Контрольные вопросы 1. Взгляните на следующие три инструкции. Изменится ли значение переменной А"г 178 Глава 6. Интерлюдил о динамической типизации А = "враз" В = А В = "влгиЬЬегу" Взгляните на следующие три инструкции. Изменится ли значение переменной А? А = ["враз"] В = А В[0] = "впгоЬЬегу" А что можно сказать об этом случае? Изменится ли значение переменной А? А = ["враз"] В=А[:] 8[0] = "влгиЬЬегу" Ответы Нет, значением переменной А по-прежнему будет строка 'враз'.
Когда переменной 8 присваивается строка 'впгьЬЬегу', она просто начинает указывать на другой строковый объект. Первоначально переменные А и В разделяют (то есть ссылаются или указывают) один и тот же строковый объект со значением ' враз ', но в языке Рут]топ два имени никак не связаны между собой. Таким образом, назначение переменной В ссылки на другой объект не оказывает влияние на переменную А. То же самое было бы справедливо, если бы последняя инструкция имела вид В = В» 'впгьЬЬегу', так как операция конкатенации создает в результате новый объект, ссылка на который затем записывается в переменную В.
Мы не можем изменять сами строковые объекты (или числа, или кортежи), потому что они относятся к категории неизменяемых объектов. Да, теперь значением переменной А будет [ "влгьЬЬвгу" ]. Формально мы не изменили ни одну из переменных, ни А, ни В, но мы изменили часть самого объекта, на который они ссылаются (указывают), посредством переменной В. Поскольку А ссылается на тот же самый объект, что и В, изменения можно обнаружить и с помощью переменной Я.
Нет, значением переменной А по-прежнему будет строка 'враз'. Изменение самого объекта с помощью ссылки В не оказывает влияние на переменную А по той причине, что выражение получения среза создает копию объекта списка, прежде чем присвоить ссылку переменной В. После второго оператора присваивания в программе будет существовать два разных объекта списков с одинаковыми значениями (в языке Ру(]топ мы говорим: »равны, но не эквивалентны»). Третья инструкция изменяет значение объекта списка, на который ссылается переменная В, а объект, на который ссылается переменная А, остается неизменным. Строки Следующий основной тип на пути нашего исследования встроенных объектов языка Ру(поп — это строки, упорядоченные последовательности символов, используемые для хранения и представления текстовой информации.
Мы коротко познакомились со строками в главе 4. Здесь мы займемся более глубоким их исследованием и восполним некоторые подробности, которые ранее были опущены. С функциональной точки зрения строки могут использоваться для представления всего, что только может быть выражено в текстовой форме: символы и слова (например, ваше имя), содержимое текстовых файлов, загруженных в память, адреса в Интернете, программы на языке РуФЬоп и т. д. Возможно, вам уже приходилось использовать строки в других языках программирования. Строки в языке Ру1Ьоп играют ту же роль, что и массивы символов в языке С, но они являются инструментом более высокого уровня, нежели простой массив символов. В отличие от С, строки в языке РуФЬоп обладают мощным набором средств для их обработки.