справочник по Python. мм isbn 9785932861578 9 785932 861578
Скачать 4.21 Mb.
|
Глава 3 . Типы данных и объекты Все данные, используемые в программах на языке Python, опираются на понятие объекта. В число объектов входят такие фундаментальные типы данных, как числа, строки, списки и словари. Однако имеется возмож- ность определять свои собственные объекты в виде классов. Кроме того, большинство объектов неразрывно связаны со структурой программы и внутренними особенностями функционирования интерпретатора. В этой главе описывается внутреннее устройство модели объектов языка Python и приводится обзор встроенных типов данных. Дальнейшее описание опе- раторов и выражений приводится в главе 4 «Операторы и выражения». По- рядок создания пользовательских объектов описывается в главе 7 «Классы и объектно-ориентированное программирование». Терминология Любой элемент данных, используемый в программе на языке Python, явля- ется объектом. Каждый объект имеет свою идентичность, тип (или класс) и значение. Например, когда в программе встречается инструкция a = 42, интерпретатор создает целочисленный объект со значением 42. Вы можете рассматривать идентичность объекта как указатель на область памяти, где находится объект, а идентификатор a – как имя, ссылающееся на эту область памяти. Тип , или класс объекта определяет его внутреннее представление, а также методы и операции, которые им поддерживаются. Объект определенного типа иногда называют экземпляром этого типа. После создания объекта его идентичность и тип не могут быть изменены. Если значение объекта может изменяться, такой объект называют изменяемым. Если значение не может быть изменено, такой объект называют неизменяемым. Объект, со- держащий ссылки на другие объекты, называется контейнером, или кол- лекцией Большинство объектов обладают определенным количеством атрибутов и методов. Атрибут – это значение, связанное с объектом. Метод – это 58 Глава 3. Типы данных и объекты функция, выполняющая некоторую операцию над объектом, когда вызы- вается, как функция. Обращение к атрибутам и методам выполняется с по- мощью оператора точки (.), как показано в следующем примере: a = 3 + 4j # Создается комплексное число r = a.real # Извлекается действительная часть (атрибут) b = [1, 2, 3] # Создается список b.append(7) # С помощью метода append в конец списка # добавляется новый элемент Идентичность и тип объекта Идентичность объекта, в виде целого числа, можно получить с помощью встроенной функции id(). Обычно это целое число соответствует адресу области памяти, где находится объект, однако это является лишь особен- ностью некоторых реализаций Python, поэтому не следует делать ника- Python, поэтому не следует делать ника- , поэтому не следует делать ника- ких предположений о природе происхождения идентичности. Оператор is сравнивает идентичности двух объектов. Встроенная функция type() возвращает тип объекта. Ниже приводятся примеры различных способов сравнивания двух объектов: # Сравнение двух объектов def compare(a,b): if a is b: # a и b ссылаются на один и тот же объект инструкции if a == b: # объекты a и b имеют одинаковые значения инструкции if type(a) is type(b): # объекты a и b имеют один и тот же тип инструкции Тип объекта сам по себе является объектом, который называется классом объекта. Этот объект уникален и всегда один и тот же для всех экземпля- ров данного типа. По этой причине типы можно сравнивать с помощью опе- ратора is. Все объекты типов имеют имена, которые можно использовать при проверке типа. Большинство этих имен, такие как list, dict и file, яв- ляются встроенными. Например: if type(s) is list: s.append(item) ёё if type(d) is dict: d.update(t) Поскольку типы могут расширяться за счет определения классов, про- верку типов лучше всего выполнять с помощью встроенной функции isinstance( object, type) . Например: if isinstance(s,list): s.append(item) ёё Подсчет ссылок и сборка мусора 59 if isinstance(d,dict): d.update(t) Ф ункция isinstance() учитывает возможность наследования, поэтому она является предпочтительным способом проверки типа любого объекта в языке Python. Хотя проверка типов объектов является легкодоступной операцией, тем не менее она не так полезна, как можно было бы подумать. Во-первых, излишние проверки ведут к снижению производительности программы. Во-вторых, в программах не всегда определяются объекты, которые чет- ко укладываются в иерархию наследования. Например, цель проверки isinstance(s,list) в предыдущем примере состоит в том, чтобы убедиться, что объект «напоминает список», но этот прием не годится для проверки объектов, которые имеют такой же программный интерфейс, что и спи- ски, но напрямую не наследуют встроенный тип list. С другой стороны, проверка типов объектов может пригодиться в случае, если в программе определяются абстрактные базовые классы. Подробнее об этом рассказы- об этом рассказы- об этом рассказы- этом рассказы- этом рассказы- рассказы- рассказы- вается в главе 7. Подсчет ссылок и сборка мусора Для всех объектов в программе ведется подсчет ссылок. Счетчик ссылок на объект увеличивается всякий раз, когда ссылка на объект записывается в новую переменную или когда объект помещается в контейнер, такой как список, кортеж или словарь, как показано ниже: a = 37 # Создается объект со значением 37 b = a # Увеличивает счетчик ссылок на объект 37 c = [] c.append(b) # Увеличивает счетчик ссылок на объект 37 В этом примере создается единственный объект, содержащий значение 37. a , – это всего лишь имя, ссылающееся на созданный объект. Когда пере- менная a присваивается переменной b, b становится еще одним именем того же самого объекта, при этом счетчик ссылок на объект увеличивается на 1. Точно так же, когда переменная b помещается в список, счетчик ссы- лок увеличивается на единицу. На протяжении всего примера существует только один объект, содержащий значение 37. Все остальные операции про- сто приводят к созданию новых ссылок на него. Счетчик ссылок уменьшается, когда вызывается инструкция del или когда поток выполнения покидает область видимости ссылки (или при присваи- вании другого значения). Например: del a # Уменьшает счетчик ссылок на объект 37 b = 42 # Уменьшает счетчик ссылок на объект 37 c[0] = 2.0 # Уменьшает счетчик ссылок на объект 37 Определить текущее количество ссылок на объект можно с помощью функ- ции sys.getrefcount(). Например: >>> a = 37 >>> import sys 60 Глава 3. Типы данных и объекты >>> sys.getrefcount(a) 7 >>> Во многих случаях количество ссылок оказывается намного больше, чем можно было бы предположить. Для неизменяемых типов данных, таких как числа и строки, интерпретатор весьма активно стремится использо- вать в разных частях программы один и тот же объект, чтобы уменьшить объем потребляемой памяти. Когда счетчик ссылок на объект достигает нуля, он уничтожается сборщи- ком мусора. Однако в некоторых случаях могут возникать циклические зависимости между коллекциями объектов, которые больше не использу- ются. Например: a = { } b = { } a[‘b’] = b # a содержит ссылку на b b[‘a’] = a # b содержит ссылку на a del a del b В этом примере инструкция del уменьшает счетчики ссылок на объекты a и b и уничтожает имена, ссылавшиеся на объекты в памяти. Однако по- скольку объекты содержат ссылки друг на друга, счетчики ссылок не до- стигают нуля и объекты продолжают существовать (что приводит к утеч- ке памяти). Чтобы исправить эту проблему, интерпретатор периодически выполняет проверку наличия циклических зависимостей, отыскивает такие недоступные объекты и удаляет их. Механизм поиска циклических зависимостей запускается периодически, как только интерпретатор обна- руживает, что в процессе выполнения программы объем занимаемой памя- ти начинает расти. Точное поведение механизма может корректироваться и управляться с помощью функций из модуля gc (см. главу 13, «Службы Python времени выполнения»). Ссылки и копии Когда в программе выполняется присваивание, такое как a = b, создает- ся новая ссылка на b. Для неизменяемых объектов, таких как числа или строки, такое присваивание фактически создает копию объекта b. Однако для изменяемых объектов, таких как списки или словари, присваивание выполняется совершенно иначе. Например: >>> a = [1,2,3,4] >>> b = a # b – это ссылка на a >>> b is a True >>> b[2] = -100 # Изменение элемента списка b >>> a # Обратите внимание, что список a также изменился [1, 2, -100, 4] >>> Объекты первого класса 61 В этом примере переменные a и b ссылаются на один и тот же объект, по- этому изменения, произведенные в одной переменной, можно наблюдать в другой. Чтобы избежать этого, необходимо вместо новой ссылки создать копию самого объекта. К контейнерным объектам, таким как списки или словари, можно приме- нить два вида копирования: поверхностное копирование и глубокое копи- рование. При поверхностном копировании создается новый объект, но он будет заполнен ссылками на элементы, которые содержались в оригинале. Например: >>> a = [ 1, 2, [3,4] ] >>> b = list(a) # Создание поверхностной копии списка a. >>> b is a False >>> b.append(100) # Добавление нового элемента в список b. >>> b [1, 2, [3, 4], 100] >>> a # Обратите внимание, что список a не изменился [1, 2, [3, 4]] >>> b[2] [0] = -100 # Изменение элемента в списке b >>> b [1, 2, [-100, 4], 100] >>> a # Обратите внимание, что изменился и список a [1, 2, [-100, 4]] >>> В данном случае a и b представляют два независимых списка, но элементы, содержащиеся в них, являются общими. Поэтому изменение одного из эле- ментов в списке a приводит к изменению элемента в списке b. При глубоком копировании создается новый объект и рекурсивно создают- ся копии всех объектов, содержащихся в оригинале. В языке Python нет встроенной функции, выполняющей глубокое копирование объектов. Од- нако в стандартной библиотеке существует функция copy.deepcopy(), при- мер использования которой приводится ниже: >>> import copy >>> a = [1, 2, [3, 4]] >>> b = copy.deepcopy(a) >>> b[2] [0] = -100 >>> b [1, 2, [-100, 4]] >>> a # Обратите внимание, что список a не изменился [1, 2, [3, 4]] >>> Объекты первого класса Все объекты в языке Python могут быть отнесены к объектам первого клас- Python могут быть отнесены к объектам первого клас- могут быть отнесены к объектам первого клас- са. Это означает, что все объекты, имеющие идентификатор, имеют одина- ковый статус. Это также означает, что все объекты, имеющие идентифика- 62 Глава 3. Типы данных и объекты тор, можно интерпретировать, как данные. Например, ниже приводится простой словарь, содержащий два значения: items = { ‘number’ : 42 ‘text’ : “Hello World” } «Первоклассную» природу объектов можно наблюдать, если попробовать добавить в этот словарь несколько необычных элементов. Например: items[“func”] = abs # Добавляется функция abs() import math items[“mod”] = math # Добавляется модуль items[“error”] = ValueError # Добавляется тип исключения nums = [1,2,3,4] items[“append”] = nums.append # Добавляется метод другого объекта В этом примере в словарь были добавлены функция, модуль, исключение и метод другого объекта. При желании можно обратиться к элементам сло- варя вместо оригинальных объектов, и такой код будет работать. Напри- мер: >>> items[“func”](-45) # Вызовет функцию abs(-45) 45 >>> items[“mod”].sqrt(4) # Вызовет функцию math.sqrt(4) 2.0 >>> try: ... x = int(“a lot”) ... except items[“error”] as e: # Идентична инструкции except ValueError as e ... print(“Couldn’t convert”) ... Couldn’t convert >>> items[“append”](100) # Вызовет метод nums.append(100) >>> nums [1, 2, 3, 4, 100] >>> Тот факт, что все объекты в языке Python являются объектами перво- Python являются объектами перво- являются объектами перво- го класса, зачастую недооценивается начинающими программистами, тогда как это позволяет писать очень компактные и гибкие програм- мы. Например, предположим, что имеется текстовая строка, такая как “GOOG,100,490.10” , и вам необходимо превратить ее в список полей, попутно выполнив необходимые преобразования типов. Ниже приводится грамот- ный способ реализации такого преобразования: создается список типов (которые также являются объектами первого класса) и выполняется не- сколько простых операций по обработке списка: >>> line = “GOOG,100,490.10” >>> field_types = [str, int, float] >>> raw_fields = line.split(‘,’) >>> fields = [ty(val) for ty,val in zip(field_types,raw_fields)] >>> fields [‘GOOG’, 100, 490.10000000000002] >>> Встроенные типы представления данных 63 Встроенные типы представления данных В языке Python существует около десятка встроенных типов данных, кото- Python существует около десятка встроенных типов данных, кото- существует около десятка встроенных типов данных, кото- рые используются для представления большинства данных в программах. Эти типы сгруппированы в несколько основных категорий, как показано в табл. 3.1. В колонке «Имя типа» перечислены имена и выражения, кото- рые можно использовать для проверки принадлежности к типу с помощью таких функций, как isinstance(). Некоторые типы данных присутствуют только в версии Python 2, – они отмечены соответствующим образом (в Py- Python 2, – они отмечены соответствующим образом (в Py- 2, – они отмечены соответствующим образом (в Py- Py- thon 3 эти типы не рекомендуются к использованию или были поглощены другими типами). Таблица 3.1. Встроенные типы представления данных Категория типов Имя типа Описание None type(None) Пустой объект None. Числа int long float complex bool Целые числа Целые числа произвольной точности (только в Python 2) Числа с плавающей точкой Комплексные числа Логические значения (True и False) Последовательности str unicode list tuple xrange Строки символов Строки символов Юникода (только в Python 2) Списки Кортежи Диапазоны целых чисел, создаваемые функцией xrange() (в версии Python 3 называется range) Отображения dict Словари Множества set frozenset Изменяемые множества Неизменяемые множества Тип None Тип None используется для представления пустых объектов (объектов, не имеющих значений). В языке Python существует ровно один пустой объ- Python существует ровно один пустой объ- существует ровно один пустой объ- ект, который в программах записывается как None. Этот объект возвраща- ется функциями, которые не имеют явно возвращаемого значения. Объект None часто используется как значение по умолчанию для необязательных аргументов, благодаря чему функция может определить, были ли переда- ны фактические значения в таких аргументах. Объект None не имеет атри- бутов и в логическом контексте оценивается как значение False. 64 Глава 3. Типы данных и объекты Числовые типы В языке Python используется пять числовых типов: логический, целые числа, длинные целые числа, числа с плавающей точкой и комплексные числа. За исключением логических значений, все остальные числовые объ- екты представляют числа со знаком. Все числовые типы относятся к раз- ряду неизменяемых. Логический тип представлен двумя значениями: True и False. Имена True и False отображаются в числовые значения 1 и 0 соответственно. Целочис- ленный тип представляет диапазон чисел от –2147483648 до 2147483647 (на некоторых аппаратных архитектурах этот диапазон может быть шире). Тип длинных целых чисел способен представлять числа неограниченной величины (ограничение накладывается только объемом доступной памя- ти). Даже при том, что существует два целочисленных типа, тем не менее интерпретатор Python старается скрыть имеющиеся различия (фактиче- Python старается скрыть имеющиеся различия (фактиче- старается скрыть имеющиеся различия (фактиче- ски, в Python 3 эти два типа были объединены в один). Поэтому, если вам доведется увидеть в программном коде упоминание о типе длинных целых чисел, в большинстве случаев это свидетельствует лишь об особенностях реализации, которые можно игнорировать, – просто используйте целочис- ленный тип во всех операциях над целыми числами. Единственное исклю- чение составляет случай проверки принадлежности значения к целочис- ленному типу. В Python 2 выражение isinstance(x, int) вернет False, если x является длинным целым числом. Числа с плавающей точкой в языке Python представлены обычными чис- лами с плавающей точкой двойной точности (64 бита). Как правило, это представление соответствует стандарту IEEE 754, который позволяет обе- IEEE 754, который позволяет обе- 754, который позволяет обе- спечивать представление примерно 17 значимых разрядов, с экспонентой в диапазоне от –308 до 308. Это полностью соответствует типу double в язы- ке C. Язык Python не поддерживает 32-битные числа с плавающей точкой одинарной точности. Если в программе потребуется иметь возможность более точно управлять точностью представления чисел и объемом зани- маемой ими памяти, можно воспользоваться расширением numpy (которое доступно по адресу: http://numpy.sourceforge.net). Комплексные числа представлены парами чисел с плавающей точкой. Дей- ствительная и мнимая части комплексного числа z доступны как атрибуты z.real и z.imag. Метод z.conjugate() возвращает сопряженное значение ком- плексного числа z (сопряженным значением для a+bj будет a-bj). Числовые типы обладают свойствами и методами, предназначенными для упрощения арифметических операций над смешанными типами чисел. Для совместимости с рациональными числами (этот тип определен в мо- дуле fractions) целые числа имеют свойства numerator и denominator. Для совместимости с комплексными числами целые числа и числа с плаваю- щей точкой имеют свойства real и imag, а также метод conjugate(). Число с плавающей точкой может быть преобразовано в пару целых чисел, пред- ставляющих дробь, с помощью метода as_integer_ratio(). Метод is_integer() проверяет, можно ли представить число с плавающей точкой как целое |