Лутц М. - Изучаем Python (1077325), страница 37
Текст из файла (страница 37)
Типы переменных Переменные не имеют никакой информации о типе или ограничениях, связанных с ним. Понятие типа присуще объектам, а не именам. Переменные универсальны по своей природе — они всегда являются всего лишь ссылками на конкретные объекты в конкретные моменты времени. Использование переменной Когда переменная участвует в выражении, ее имя замещается объектом, на который она в настоящий момент ссылается, независимо от того, что это за объект. Кроме того, прежде чем переменную можно будет использовать, ей должно быть присвоено значение — использование неинициализированной переменной приведет к ошибке.
Эта модель существенно отличается от традиционных языков программирования. Динамическая типизация обычно проще поддается пониманию начинающих, особенно если они четко осознают разницу между именами и объектами. Например, если ввести такую инструкцию: »> а = 3 интерпретатор РуФ)топ выполнит эту инструкцию в три этапа, по крайней мере, концептуально. Следующие этапы отражают все операции присваивания в языке РуФ)топ: 1.
Создается объект, представляющий число 3. 2. Создается переменная а, если она еще отсутствует. 3, Переменная связывается с новым объектом, представляющим число 3. 168 Глава б. Интерлюдия о динамической типизации Результатом выполнения этих этапов будет структура, которая показана на рис. 6.1. Как показано на схеме, переменные и объекты хранятся в разных частях памяти и связаны между собой ссылкой (ссылка на рисунке показана в виде стрелки). Переменные всегда ссылаются на объекты и никогда на другие переменные, но крупные объекты могут ссылаться на другие объекты (например, объект списка содержит ссылки на объекты, которые включены в список).
Эти ссылки на объекты в языке РусЬоп так и называются ссылки, то есть ссылки — это своего рода ассоциативная связь, реализованная в виде указателя на область памяти.' Когда бы ни использовалась переменная (то есть ссылка), интерпретатор РусЬоп автоматически переходит по ссылке от переменной на объект. Все на самом деле гораздо проще, чем кажется. В конкретных терминах: ° Переменные — это записи в системной таблице, где предусмотрено место для хранения ссылок на объекты. ° Объекты — это области памяти с объемом, достаточным для представления значений этих объектов. ° Ссылки — это автоматически разыменовываемые указатели на объекты. Всякий раз,по крайней мере концептуально, когда в сценарии в результате выполнения выражения создается новое значение, интерпретатор Ру$Ьоп создает новый объект (то есть выделяет область памяти), Рис.
6.1. Имена и перемен ньге после выполнения операции присваивания а = 3. Переменная превращается в ссылку на объект 3. Во внутреннем представлении переменная в действительности является указателем на пространство памяти с объектом, созданным в результате интерпретации литерального выражения 3 Читатели, знакомые с языком С, сочтут, что между ссылками в языке РутЬоп н указателями в языке С много общего (адреса в памяти). И действительно, ссылки реализованы как указатели н они часто играют ту же роль, особенно когда объект относится к категории изменяемых (подробнее об этом будет говориться ниже). Однако, так как ссылки при использовании всегда автоматически разыменовываются, вы никак не сможете использовать саму ссылку — эта особенность ликвидирует огромный пласт ошибок, которые можно допустить в языке С.
Вы можете считать ссылки указателями типа гто1дв в языке С, которые автоматически разыменовываются прн любом использовании. 1б9 Отсутствие инструкций объявления представляющий это значение. Внутренняя реализация интерпретатора, с целью оптимизации, кэширует и повторно использует некоторые типы неизменяемых объектов, такие как малые целые числа и строки (каждый 0 в действительности не является новой областью в памяти, но подробнее о механизме кэширования мы поговорим позже). Но с логической точки зрения все выглядит так, как если бы результат каждого выражения был представлен отдельным объектом и каждый объект занимал отдельную область памяти.
С технической точки зрения объекты имеют более сложную структуру, чем просто пространство в памяти, необходимое для хранения значения. Каждый объект имеет два стандартных поля: указатель ютила, используемый для хранения информации о типе объекта, и счетчик ссылок, используемый для определения момента, когда память, занимаемая объектом, может быть освобождена. Чтобы понять, какую роль играют эти два поля в модели динамической типизации, нам необходимо двинуться дальше.
Информация о типе хранится в объекте, но не в переменной Чтобы увидеть, как используется информация о типах объектов, посмотрим, что произойдет, если выполнить несколько операций присваивания одной и той же переменной: »> а 3 л Это пелое число »> а = 'ерав' л тепер~ это строке »> а = 3.23 л Теперь это число с плеееююей точкой Это не совсем типичный программный код на языке Ру1йоп, но он работает — сначала создается целое число, потом строка и, наконец, число с плавающей точкой. Этот пример особенно странно выглядит для программистов, использовавших язык С, поскольку он выглядит так, как если бы при выполнении инструкции 3 = 'зраа' производилось изменение типа переменной с целочисленного на строковый. Однако в действительности этого не происходит.
В языке РуФЬоп все реализовано намного проще: имена не имеют типов, как уже указывалось ранее, тип — это свойство объекта, а не имени. В предыдущем листинге просто изменяется ссылка на объект. Так как переменные не имеют типов, мы в действительности не изменяем типы переменных — мы просто записываем в переменные ссылки на объекты других типов. На самом деле все, что можно сказать о переменных в языке РуФЬоп, — это то, что они ссылаются на конкретные объекты в конкретные моменты времени. С другой стороны, объекты знают, к какому типу они относятся, — каждый объект содержит поле, в котором хранится информация о его типе. Целочисленный объект 3, например, будет содержать значение 3 плюс информацию, которая сообщит интерпретатору Руо>оп, что объект является целым числом (строго говоря — это указатель на объект 170 Глава б.
Интерлюдия о динамической типизации с названием тпт„которое играет роль имени целочисленного типа). Указатель типа для строки 'враз' указывает на строковый тип (с именем в! г). Поскольку информация о типе хранится в объектах, ее не нужно хранить в переменных. Итак, типы в языке Ру[)топ — это свойства объектов, а не переменных. В типичном программном коде переменная обычно ссылается на объекты только одного типа. ['ак как для языка РуЫтоп это не является обязательным требованием, программный код на языке Рус[топ обладает более высокой гибкостью, чем вам может показаться, — при умелом использовании особенностей языка программный код смог бы работать со многими типами автоматически.
Я уже упоминал, что каждый объект имеет два поля — указатель типа и счетчик ссылок. Чтобы разобраться с последним из них, нам нужно пойти еще дальше и взглянуть, что происходит в конце жизненного цикла объекта. Объекты уничтожаются автоматически В листинге из предыдущего раздела мы присваивали одной и той же переменной объекты различных типов. Но что происходит с прежним значением, когда выполняется новое присваиваниег Например, что произойдет с объектом 3 после выполнения следующих инструкций: »> а = 3 »> а = 'враз' Дело в том, что всякий раз, когда имя ассоциируется с новым объектом, интерпретатор РУФ)топ освобождает память, занимаемую предыдущим объектом (если на него не ссылается какое-либо другое имя или объект). такое автоматическое освобождение памяти, занимаемой объектами, называется сборкой мусора (уаг(>ауе сояесвоп).
Чтобы проиллюстрировать сказанное, рассмотрим следующий пример, где с имя х ассоциируется с разными объектами при выполнении каждой операции присваивания: »>х=42 »> х = 'вягиЬЬегу' 4 освобождается обьект 42 Геспи иет других ссипок) »> х = 3.!415 4 Тепер~ освобождается обьект 'ввгоЬСегу' »> х = [1, 2, 3) Ф Теперь освобождается объект 3. 7415 Первое, что следует отметить, — каждый раз с именем х связывается объект другого типа. Снова, хотя в действительности это не так, возникает ощущение изменения типа переменной х с течением времени.