Готовый перевод The Python Language Reference / Справочник по языку Python: 3. Модель данных
3. Модель данных
3.1. Объекты, значения и типы
Объекты в Python являются абстракцией для данных. Все данные в программе на Python представлены объектами или взаимоотношениями между объектами. (В определенном смысле, и в соответствии с моделью "сохраняемых компьютерных программ" Фон Неймана, код также представляется объектами.)
Каждый объект имеет идентификатор, тип и значение. Идентификатор объекта никогда не изменяется после создания объекта, его можно представить себе как адрес объекта в памяти. Оператор 'is' сравнивает идентификаторы двух объектов; функция id() возвращает целое число, представляющее идентификатор (на текущий момент реализованный как адрес объекта). Тип объекта так же неизменяем. [1] Тип объекта определяет операции, поддерживаемые объектом (например, имеет ли объект длину), а также возможные значения для объекта заданного типа. Функция type() возвращает тип объекта (который в свою очередь является объектом). Значение некоторых объектов может меняться. Объекты, значение которых может меняться называются изменяемыми; объекты, значение которых не может быть изменено после создания называются неизменяемыми. (Значение неизменяемого объекта - контейнера, который содержит ссылки на изменяемые объекты может меняться когда значение последних изменено, тем не менее контейнер рассматривается как неизменяемый, потому что набор содержащихся в нем объектов не может быть изменен. Т.о., неизменяемость это в точности то же самое, что и неизменное значение объекта, это более точный термин.). Изменяемость объекта определяется его типом; например, числа, строки и записи неизменяемы, тогда как словари и списки изменяемы.
Объекты никогда явно не уничтожаются, тем не менее, когда они становятся недоступны они могут быть обработаны Сборщиком мусора. В реализации возможны поздняя сборка мусора или полное ее отсутствие. Каким образом реализована сборка мусора - это вопрос качества реализации. До тех пор пока объекты не собраны сборщиком мусора, они все еще доступны.
Нюанс реализации CPython: в настоящее время CPython использует схему подсчёта ссылок с (опционально) отсрочкой определения циклически связанного мусора, которая собирает большинство объектов, как только они становятся недоступными, но не гарантируется сборка мусора, содержащего циклические ссылки. Смотрите документацию модуля gc, чтобы узнать о контроле сбора циклического мусора.
Обратите внимание, что использование данной реализации трассировки или отладки может сохранить объекты, которые, обычно собрались бы. Отметим также, что обработка исключения ‘try...except‘ выражением, может сохранить объекты.
Некоторые объекты содержат ссылки на "внешние" ресурсы, такие как открытые файлы или окна. Понятно что эти ресурсы освобождаются при сборке мусора, однако поскольку не гарантировано что сбор мусора произойдет, то такие объекты также имеют способ освобождения внешних ресурсов как правило, Close() методом. В программах настоятельно рекомендуется закрывать такие объекты. Для этого удобно использовать блоки ‘try...finally‘ и ‘with‘.
Некоторые объекты содержат ссылки на другие объекты; они называются контейнерами. Примеры контейнеров, это кортежи, списки и словари. Ссылки являются частью значений контейнера. В большинстве случаев, когда мы говорим о значении контейнера, мы подразумеваем значения, а не тождества хранимых объектов; однако, когда мы говорим о изменчивости контейнера, подразумеваются только тождества хранимых в данный момент объектов. Поэтому, если неизменный контейнер (как, например, кортеж) содержит ссылку на изменяемый объект, его значение меняется, если меняется этот изменяемый объект.
Типы влияют почти на все аспекты поведения объекта. Даже важность тождественности объекта в какой-то степени подвержена этому влиянию: для неизменяемых типов, операции, которые вычисляют новые значения могут в действительности возвращать ссылку на какой-либо существующий объект такого-же типа и с таким-же значением, тогда как для изменяемых объектов это не допустимо. Например, после a = 1; b = 1, a и b могут ссылаться на один и тот же объект (а могут и на разные), имеющий значение "единица", что зависит от конкретной реализации, но после c = []; d = [], c и d обязательно ссылаются на два различных, уникальных, заново созданных пустых списка. (Заметьте, что c = d = [] присваивает один и тот же объект и c и d.)
3.2 Иерархия стандартных типов
Ниже в некоторых описаниях типов содержится абзац, перечисляющий "специальные атрибуты". Это атрибуты, которые предоставляют доступ к внутреннему устройству интерпретатора. В норме (кроме экспериментов над функциональностью интерпретатора, наладки и прочих исключительных случаев) их употреблять не следует - поскольку их определение может измениться в будущем.
None
Этот тип может иметь только единственное значение. И имеется только единственый объект с этим значением. Доступ к этому объекту происходит через встроенное имя "None". Во многих ситуациях он используется, чтобы обозначить отсутствие значения, например он возвращается из функций, которые не возвращают ничего явным образом. "None" имеет значение истинности: "false"("ложь").
NotImplemented
Этот тип может иметь только единственное значение. И имеется только единственый объект с этим значением. Доступ к этому объекту происходит через встроенное имя "NotImplemented". Числовые методы и методы сравнения могут вернуть это значение, если они не имеют реализации данной операции для данных операндов. (...) "NotImplemented" имеет значение истинности: "true"("истина").
Многоточие («ellipsis»)
Этот тип может иметь только единственное значение. И имеется только единственый объект с этим значением. Доступ к этому объекту происходит через запись "..." (троеточие), или встроенное имя "Ellipsis". "Ellipsis" имеет значение истинности: "true"("истина").
numbers.Number
Объекты этого типа создаются непосредственной записью числа, а также возвращаются как результат арифметическими операторами и арифметическими встроенными функциями. Числовые объекты являются неизменяемыми ("immutable") - будучи однажды созданным, их значение никогда не меняется. Питоновские числа, конечно, ассоциируются с числами, как они понимаются в математике, только они имеют ограничения компьютерного числового представления.
Питон различает целые, комплексные и числа с плавающей запятой :
numbers.Integral
Представляют собой элементы математического множества целых (положительных и отрицательных) .
Есть два типа целых :
Integers (int)
Этот тип представляет целые числа в теоретически неограниченном диапазоне, ограничиваясь только доступной памятью (виртуальной). При выполнении операций сдвига и маскирования подразумевается двоичная запись числа, и отрицательные числа представлены в варианте двоичного дополнительного кода, который даёт впечатление бесконечного ряда знаковых битов, распространяющихся влево.
Booleans («bool», «логические», «булевы»)
Этот тип представляет значения истинности - "False" и "True". Только два объекта, представляющие "False" и "True", являются булевыми(логическими). Булевый - является подтипом целых, и булевые значения ведут себя как значения "0" и "1" (для "false" и "true" соответственно) - почти во всех контекстах - с тем исключением, что при конвертации в строку возвращаются строки "False" или "True".
Правила представления целых нацелены на наиболее функциональную интерпретацию операций сдвига и маскирования для целых чисел, включая отрицательные.
numbers.Real (float)
Представляют собой машинную реализацию чисел с плавающей запятой двойной точности. Приходится полностью полагаться на архитектуру машины, на которой происходит исполнение (и на реализацию «C» или «Java») , в отношении диапазона и обработки переполнения. Питон не поддерживает числа с плавающей запятой одинарной точности – экономия ресурсов процессора и памяти, которая обычно является причиной их использования, перечёркивается дополнительными затратами при использовании объектов Питона, так что нет причин усложнять язык двумя видами чисел с плавающей запятой.
numbers.Complex (complex)
Этот тип определяет комплексные числа, как пары зависящих от машинной реализации чисел двойной длины с плавающей точкой. Для них действительны те же ограничения, что и для чисел с плавающей точкой. Значения вещественной и мнимой частей комплексного числа z могут быть получены с помощью атрибутов (только для чтения) z.real и z.imag.
Последовательности
Этот тип представляет ограниченое (не бесконечное) упорядоченое множество, индексированное неотрицательными целыми числами. При длинне последовательности n множество индексов содержит числа 0, 1, ..., n-1. Элемент i последовательности a адресуется записью "a[i]".
Для последовательностей также доступно вырезание ("срезы", "slices"). Так "a[i:j]" выбирает все элементы с индексом k, таким, что i <= k < j. При использовании в качестве выражения, срез является последовательностью того же типа, что и исходная последовательность. При этом множество индексов заново перечисляется, начиная с 0.
Некоторые последовательности также поддерживают "расширенные срезы" с третьим параметром "шаг". Так "a[i:j:k]" выбирает все элементы из a с индексом x , где x = i + n*k, n >= 0 , i <= x < j.
Последовательности различаются с точки зрения их изменяемости :
Неизменяемые последовательности
Объект принадлежащий к типу неизменяемой последовательности не может изменяться с момента создания. (Если же этот объект содержит ссылки на другие объекты, то уже́́́ эти другие объекты могут оказаться изменяемыми - и могут меняться; однако тот набор объектов, на которые непосредственно ссылается неизменяемый объект, меняться не может.
Следующие типы являются неизменяемыми последовательностями :
Строки
Элементами текстового ("строкового") объекта являются элементарные(минимальные) единицы(порции) кода Юникод. Код символа Юникод реализуется текстовым объектом из одного символа и может использовать 16- или 32-битное значение, означающее номер символа Юникод (максимальное значение для этого номера задано в "sys.maxunicode" , и зависит от того, как Питон сконфигурирован при компиляции). Могущие присутствовать В Юникодном объекте "суррогатные" пары будут восприниматься как два отдельных объекта. Встроенные функции "chr()" и "ord()" выполняют преобразование между односимвольным текстовым объектом и неотрицательным целым числовым объектом с соответствующим значением номера символа Юникода, как определено в "Unicode Standard 3.0" . Преобазования из и в другие кодировки возможны с помощью метода "encode()" .
Кортежи ("tuples")
Элементами "кортежа" могут быть любые объекты Питона. Кортежи из двух и более элементов образуются перечнем выражений, разделённых запятыми. Кортеж из одного элемента ("singleton") может быть образован добавлением запятой после выражения (само выражение без запятой - не создаёт кортеж, поскольку в таком случае скобки обозначают группирование в выражении). Пустой кортеж может быть образован пустой парой скобок.
Байты
Байтовый объект является неизменяемым массивом. Его элементами являются 8-битовые байты, которые могут быть представлены целыми числами в диапазоне 0 <= x < 256. Для создания байтовых объектов можно использовать непосредственную запись байтов (как например " b'abc' "), или встроенную функцию "bytes()". Кроме того, байтовые объекты могут быть перекодированы в строковые с помощью метода "decode()".
Изменяемые последовательности
Изменяемые последовательности могут быть изменены после их создания. Нотация подписки и нарезки может быть использована в качестве цели присваивания и del (delete) выражения.
В данной версии есть два типа изменяемых последовательностей:
Списки
Элементами списка могут быть любые объекты Питона. Списки задаются перечислением выражений через запятую внутри пары квадратных скобок. (Заметьте, что нет специальной формы для списка пустого или с одним элементом.)
Массивы байтов
Объект типа массив байтов является изменяемым массивом. Они создаются встроенным конструктором "bytearray()". За исключением изменяемости, байтовые массивы в остальном предоставляют теже интерфейс и функциональность как и неизменяемые байтовые объекты.
Модулях расширения «array» и «collections» предоставлены дополнительные варианты типов изменяемых последовательностей.
Типы множеств
Эти типы представляют неупорядоченные, конечные наборы неповторяющихся объектов. В связи с этим к ним не могут применяться операции выбора элементов по их индексу. Однако элементы наборов могут быть последовательно перебраны ("итерированы"), а также можно получить их количество с помощью встроенной функции "len()". Обычно наборы находят применение для быстрого определения вхождения во множество, для удаления повторов из последовательностей и для проведения операций типа пересечения, объединения, разности.
Для элементов наборов применяются теже правила неизменяемости, как и для ключей словарей. Обратите внимание, что для числовых типов реализуются обычные правила сравнения чисел : если два числа равны (с точки зрения операции сравнения, как например "1" и "1.0"), то только одно может присутствовать в наборе.
В данной версии языка существует два внутренних наборных типа :
Наборы
Этот тип представляет изменяемый набор. Наборы создаются встроенным конструктором "set()" и впоследствии могут быть изменены с помощью некоторых "методов" - например "add()".
Фиксированые наборы ("Frozen sets")
Этот тип представляет неизменяемый набор. Они создаются встроенным конструктором "frozenset()". Поскольку они неизменяемые - они могут в свою очередь быть использованы как элемент другого набора, или как ключ словаря.
Отображения
Это конечные наборы объектов, индексированных произвольным набором индексов. Запись индексирования (извлечения) "a[k]" выбирает элемент, индексированный значением "k" , из отображения "a" . Такая запись может использоваться в выражениях и как получатель значения или с инструкцией "del" . Встроенная функция "len()" возвращает количество элементов в отображении.
В данной версии есть единственный тип отображения :
Словари
Словари - это конечные множества объектов, индексируемых соответственно элементами (которые могут быть практически любыми значениями) другого набора той же длины. Единственными типами значений, недопустимыми в качестве индекса (ключа), являются значения, содержащие списки или словари или другие изменяемые типы, сравнение которых производится по значению, а не по идентификатору, по причине того, что для эффективной реализации словарей требуется, чтобы значения хешей ключей оставались неизменяемыми. для числовых типов, используемых в качестве ключей, реализуются обычные правила сравнения чисел : если два числа равны (с точки зрения операции сравнения, как например "1" и "1.0"), то они являются взаимозаменяемыми и любое из них может может быть использовано в качестве ключа к одной и той же записи словаря.
Словари являются изменяемыми. Они могут быть созданы с помощью записи "{...}".
В модулях расширения «dbm.ndbm» и «dbm.gnu» предоставлены дополнительные варианты типов отображений.
Исполнимые (вызываемые) типы
Это типы, к которым применима операция вызова (исполнения) функции (смотрите раздел "Вызовы") :
Функции определяемые пользователем
Объект функции определяемой пользователем создаётся определением функции (смотрите раздел "Определения функций"). Её следует вызывать со списком, содержащим ровно то же количество аргументов, что и в списке формальных параметров этой функции.
Специальные атрибуты :
Атрибут
Значение
__doc__
Строка описания ("документации") данной функции, или иначе значение "None".
Изменяемый
__name__
Имя данной функции.
Изменяемый
__module__
Имя модуля, в котором данная функция была определена, или иначе значение "None".
Изменяемый
__defaults__
Кортеж, содержащий значения по умолчанию для аргументов, для которых они определены, или значение "None", если нет аргументов со значением по умолчанию.
Изменяемый
__code__
Объект кода, представляющий компилированное тело данной функции.
Изменяемый
__globals__
Ссылка на словарь, содержащий глобальные переменные данной функции — глобальная область имён того модуля, в котором данная функция была определена.
Только для чтения
__dict__
Пространство имён для любых атрибутов данной функции.
Изменяемый
__closure__
Кортеж ячеек, содержащих назначения для свободных переменных данной функции.
Только для чтения
__annotations__
Словарь, содержащий описания параметров. Ключи этого словаря совпадают с именами параметров к этой функции, ещё может быть ключ " 'return' " для соответствующего описания, если выходной параметр "return" используется явно.
Изменяемый
__kwdefaults__
Словарь, содержащий значения по умолчанию для параметров keyword-only.
Изменяемый
Большинство атрибутов помеченных "Изменяемый" проверяют тип записываемого в них значения.
Объекты-функции также поддерживают получение и установку произвольных атрибутов, которые могут быть использованы, например, для прикрепления метаданных к функциям. Для получения и установки таких атрибутов используется стандартная запись атрибутов через точку. Обратите внимание, что текущая реализация поддерживает только атрибуты пользовательских функций. Атрибуты встроенных функций могут быть реализованы в будущем.
Дополнительная информация об определении функции может быть получена из ее объекта кода; см.описание встроенных типов ниже.
Методы экземпляров
Объект метода экземпляра сочетает в себе класс, экземпляр класса и любой вызываемый объект (обычно - функция, определяемая пользователем).
Специальные атрибуты, доступные только для чтения : __self__ это данный объект экземпляра класса, __func__ это данный объект функции; __doc__ это описание данного метода (то же, что и __func__.__doc__); __name__ это имя данного метода (то же, что и __func__.__name__); __module__ это имя того модуля, в котором данный метод был определен, или, если не применимо - "None".
Методы также поддерживают доступ (но не запись) к произвольному атрибуту функции в том же самом объекте функции.
Определяемые пользователем объекты методы могут быть созданы при получении атрибутов класса (возможно, через какой-либо экземпляр этого класса), если этот атрибут является пользовательским объектом функцией или объектом метода класса.
Когда объект метода экземпляра создается путем получения пользовательского объекта функции из какого-либо класса через один из его экземпляров, его атрибут "__self__" является этим же экземпляром, и этот объект метода называется связанным. Атрибут "__func__" этого нового метода является оригинальным объектом функции.
Когда определяемый пользователем метод создается путем извлечения другого объекта метода из класса или экземпляра, его поведение остается таким же, как у функционального объекта, за исключением того, что атрибут __func__ нового экземпляра является не исходным методом объекта, а его атрибутом __func__.
Когда объект экземпляра метода создается путем извлечения метода класса объекта из класса или экземпляра, его атрибут __self__ - это сам класс, а его атрибут __func__ - это объект функции лежащей в основе метода класса.
Когда вызывается объект метода экземпляра, вызывается содержащаяся в его основе функция (__func__), помещающая экземпляр класса (__self__) в начало списка аргументов. Например, если C - класс, содержащий определение функции f(), а x - экземпляр класса C, вызов x.f(1) эквивалентен вызову C.f(x, 1).
Если объект метода экземпляра не определён в этом экземпляре, а унаследован от объекта метода класса, то атрибут "__self__" на самом деле будет указывать не на этот экземпляр класса, а непосредственно на сам класс, и, таким образом, вызов и "x.f(1)" и "C.f(1)" является эквивалентом вызову "f(C,1)" , где f - соответствующая функция.
Отметим, что преобразование из объекта функции в объект метода экземпляра происходит каждый раз при извлечении атрибута из экземпляра. В некоторых случаях эффективной оптимизацией является назначение атрибута локальной переменной и вызов этой локальной переменной. Также учитывайте, что это преобразование выполняется только для функций, определенных пользователем; прочие вызываемые объекты (и все невызываемые объекты) извлекаются без преобразования. Важно заметить, что такие определенные пользователем функции, которые являются атрибутами экземпляров классов, не преобразуются в связанные методы; это происходит только если функция является атрибутом класса.
Функции-генераторы
Функция или метод, задействующие инструкцию «<code>yield</code>» (смотрите раздел 6.7. Инструкция «yield» ) , называется : функция-генератор. При вызове такая функция всегда возвращает объект-итератор, который может быть использован для выполнения тела функции – вызов метода «<code>__next__()</code>» данного итератора приведёт к исполнению данной функции, пока она предоставляет какое-либо значение с использованием инструкции «<code>yield</code>» . Когда данная функция исполняет инструкцию «<code>return</code>» или достигает своего конца – вызывается исключение «<code>StopIteration</code>» – и объект-итератор таким образом достигнет конца множества значений, которые он должен выдать.
Встроенные функции
Объект - встроенная функция – это посредник к функции на «C» . Примерами встроенных функций являются : «<code>len()</code>» и «<code>math.sin()</code>» ( «<code>math</code>» – стандартный встроенный модуль) . Количество и тип её аргументов определяется соответствующей функцией на «C» . Особые доступные только для чтения атрибуты : «<code>__doc__</code>» – текст документации данной функции или иначе «<code>None</code>» ; «<code>__name__</code>» – имя данной функции; «<code>__self__</code>» – установлен в «<code>None</code>» (но далее смотрите об этом подробнее) ; «<code>__module__</code>» – имя модуля, в котором определена данная функция или иначе «<code>None</code>» .
Встроенные методы
Это, по сути, другое обличие встроенных функций, которые в этом случае имеют дополнительный аргумент, передаваемый в функцию на «C» неявно. Примером встроенного метода является «<code>alist.append()</code>» , где «<code>alist</code>» – это объект-список. В таком случае особый предназначенный только для чтения атрибут «<code>__self__</code>» содержит указание на этот объект.
Классы
Классы являются вызываемыми (исполняемыми) объектами. Как правило, они работают как фабрики для новых собственных экземпляров класса, при этом генерация может проходить с вариациями у таких типов классов, в которых переопределён метод "__new__()" . Аргументы вызова передаются методу "__new__()" и, как правило, методу "__init__()" для инициализации нового экземпляра.
Экземпляры класса
Экземпляры любого класса могут быть сделаны вызываемыми (исполнимыми) посредством определения метода "__call__()" в их классе.
Модули
Модули импортируются с помощью инструкции "import" (смотрите раздел : Инструкция "import"). Объект модуль имеет область имён реализованую в виде объекта словарь в атрибуте "__dict__" (это тот самый словарь, на который ссылается атрибут "__globals__" функций определеных в этом модуле). Указания атрибутов преобразуются в поиск в этом словаре, например, "m.x" эквивалентно "m.__dict__['x']". Объект модуль не содержит объект код, используемый для инициализации этого модуля (поскольку инициализация уже произведена, и он больше не может понадобиться).
Назначение атрибуту, по сути, обновляет словарь области имён модуля, например "m.x = 1" эквивалентно "m.__dict__['x'] = 1" .
Специальный атрибут только для чтения : "__dict__" - область имён модуля, в виде объекта словарь.
Предопределённые изменяемые атрибуты : "__name__" - имя данного модуля; "__doc__" - строка описания данного модуля, или иначе значение "None" ; "__file__" - путь файла, из которого загружен данный модуль, если он был загружен из файла. Атрибут "__file__" отсутствует в модулях на "C" , которые статически прилинкованы к интерпретатору; для модулей расширений, подгруженных динамически из общих библиотек - он является путём файла соответствующей общей библиотеки.
Классы, определяемые пользователем
Типы определяемых классов, как правило, создаются определением класса (смотрите раздел "Определения классов"). Класс имеет область имён реализованую в виде объекта словарь. Указания атрибутов класса преобразуются в поиск в этом словаре, например, "C.x" заменяется на "C.__dict__['x']" (хотя есть ряд трюков, которые позволяют разместить атрибуты другим путём). Когда имя данного атрибута там не найдено, поиск атрибута продолжается в базовых классах. Такой поиск базовых классов использует порядок разрешения метода C3, который ведет себя правильно, даже в случае структуры наследования типа "diamond", тоесть, где есть несколько путей наследования сходящихся обратно к одному общему предку. Дополнительную информацию об C3 MRO можно найти в документации, сопровождающей релиз 2.3 по адресу : "http://www.python.org/download/releases/2.3/mro/".
Когда указание на атрибут класса (назовём класс «<code>C</code>») должно давать объект - метод класса – он преобразуется в объект - метод экземпляра, чей атрибут «<code>__self__</code>» имеет значение «<code>C</code>» . А когда это указание должно давать объект - статический метод – он преобразуется в тот же объект «обёрнутый» объектом - статическим методом. Другие варианты, того как атрибуты, получаемые из класса, могут отличаться от реально содержащихся в их атрибуте «<code>__dict__</code>» – смотрите в разделе «Реализация дескрипторов» .
Запись значений в атрибуты класса модифицирует словарь этого класса, но ни в коем случае не соответствующий словарь базового класса.
Объект класс может быть вызван (запущен на исполнение), как упомянуто выше, чтобы сгенерировать экземпляр класса (смотрите ниже).
Специальные атрибуты: "__name__" - имя класса; "__module__" - имя модуля, в котором был определен этот класс; "__dict__" - словарь, содержащий область имён этого класса; "__bases__" - кортеж (возможно, пустой или с одним элементом ("Singleton")), содержащий базовые классы, в порядке их появления в списке базовых классов; "__doc__" - строка описания данного класса, или иначе значение "None".
Экземпляры классов
Экземпляр класса создается путем вызова объекта класс (см. выше). Экземпляр класса имеет область имён, реализованную в виде словаря, который является первым местом, в котором ищутся атрибуты. Если атрибут здесь не найден, а класс этого экземпляра имеет атрибут с таким именем, поиск продолжается в атрибутах класса. Если становится известно, что некий атрибут класса является объектом функцией пользователя, он преобразуется в объект метод экземпляра, чей атрибут "__self__" является тем экземпляром. Статические методы и объекты методы класса также преобразуются, см. выше в разделе "Классы". Смотрите также в разделе "Реализация дескрипторов" другой путь, которым атрибуты класса, полученного через его экземпляры, могут отличаться от объектов, на самом деле хранящихся в атрибуте "__dict__" этого класса. Если атрибут класса не найден, но класс этого объекта имеет метод "__getattr__()", то этот метод вызывается и возвращаемое им значение возвращается в качестве значения искомого атрибута.
Запись значения в атрибуты и их удаление обновляют словарь экземпляра. Если класс имеет методы "__setattr__()" или "__delattr__()", то вызываются они - вместо обновления словаря экземпляра напрямую.
Экземпляры класса могут вести себя как числа, последовательности или отображения, если у них есть методы с определёнными специальными именами. См. раздел "Имена специальных методов".
Специальные атрибуты: "__dict__" - словарь атрибутов; "__class__" - класс данного экземпляра.
Файлы
Файловый объект представляет собой открытый файл. Файловые объекты создаются встроенной функцией "open()", а также функциями "os.popen()", "os.fdopen()", и методом "Makefile()" объектов сокетов (и, возможно, другими функциями или методами, предоставляемыми модулями расширения ). Объекты sys.stdin, sys.stdout и sys.stderr инициализируются в файловые объекты, соответствующие стандартным вводу, выводу и потоку ошибок интерпретатора. См. "Файловые объекты" для полного описания файловых объектов.
Внутренние типы
Несколько типов, используемых для внутренних целей интерпретатором, предоставяются пользователю. Их определения могут измениться в будущих версиях интерпретатора, но они упоминаются здесь для полноты.
Объекты кода
Объекты кода представляют собой скомпилированный в байт-код исполняемый код Питона. Разница между объектом кода и объектом функции заключается в том, что объект функции содержит явное указание на область имён, в которой содержатся глобальные переменные функции (модуль, в котором она была определена), а объект кода не содержит указания на такой контекст; также в объекте функции хранятся значения по умолчанию аргументов, а в объекте кода их нет (так как они представляют собой значения, рассчитываемые во время выполнения). В отличие от объектов функций, объекты кода являются неизменяемыми и не содержать ссылок (прямо или косвенно) на изменяемые объекты.
Специальные атрибуты только для чтения:
"co_name" содержит имя данной функции;
"co_argcount" это количество позиционных аргументов (в том числе аргументов со значениями по умолчанию);
"co_nlocals" это число локальных переменных, используемых функцией (включая аргументы);
"co_varnames" кортеж, содержащий имена локальных переменных (начиная с имен аргументов);
"co_cellvars" кортеж, содержащий имена локальных переменных, на которые ссылаются вложенные функции;
"co_freevars" кортеж, содержащий имена свободных переменных;
"co_code" строка, представляющая последовательность байт-код инструкций;
"co_consts" кортеж, содержащий непосредственные данные используемые байт-кодом;
"co_names" кортеж, содержащий имена, используемые байт-кодом;
"co_filename" имя файла, из которого код был скомпилирован;
"co_firstlineno" номер первой строки функции;
"co_lnotab" текст, кодирующий соответствие смещения байт-кодов номерам строк текста программы (подробнее см. исходный код интерпретатора);
"co_stacksize" требуемый размер стека (включая локальные переменные);
"co_flags" целое число, в котором закодировано некоторое количество параметров(флагов) интерпретатора.
Следующие сигнальные биты определены внутри "co_flags" : бит 0x04 установлен, если данная функция использует синтаксис "*arguments" для принятия произвольного количеотва позиционных аргументов; бит 0x08 установлен, если данная функция использует синтаксис "**keywords" для принятия произвольных именованных аргументов; бит 0x20 установлен, если функция является генератором.
Инструкция «<code>from __future__ import division</code>» также использует биты в «<code>co_flags</code>» для обозначения того, был ли объект-код скомпилирован со включенными определёнными свойствами. Так, бит «<code>0x2000</code>» установлен, если данная функция скомпилирована с задействованием «future division» . Биты «<code>0x10</code>» и «<code>0x1000</code>» использовались в более ранних версиях Питона.
Другие биты в "co_flags" - зарезервированы для внутреннего использования.
Если объект кода является функцией, то первый элемент в "co_consts" содержит текст описания (документацию) данной функции, или значение "None" .
Объекты-кадры
Объекты-кадры реализуют кадры исполнения. Они могут встречаться в объектах раскрутки стека (смотри́те далее) .
Специальные атрибуты только для чтения: «<code>f_back</code>» указывает предыдущий кадр стека (в сторону вызывающего), или «<code>None</code>» если это дно стека; «<code>f_code</code>» является объектом-кодом, выполняющимся в данном кадре; «<code>f_locals</code>» является словарём, использующимся для поиска локальных переменных; «<code>f_globals</code>» используется для глобальных переменных; «<code>f_builtins</code>» используется для встроенных (внутренних) имён; «<code>f_lasti</code>» дает точные инструкции (это индекс в массиве байт-кода у объекта кода) .
Специальные перезаписываемые атрибуты: «<code>f_trace</code>» , если не «:const:None» , является функцией, вызываемою в начале каждой строки исходного кода (это используется отладчиком); «<code>f_lineno</code>» содержит номер текущей строки кадра – запись сюда изнутри функции отслеживания (трассирования) приводит к переходу на данную строку (только для самого нижнего кадра) . Отладчик может реализовать команду “Jump” , путём записи в «<code>f_lineno</code>» .
Объекты раскрутки стека
Объекты раскрутки стека представляют раскрутку стека исключений. Объект раскрутки стека создается при возникновении исключения. Когда поиск обработчика исключения раскручивает стек вызовов, на каждом уровне новый объект раскрутки стека вставляется перед текущим. Когда обработчик исключения найден, раскрутка стека делается доступной для программы. (Смотри́те раздел “Инструкция «try»” .) Она доступна в качестве третьего элемента кортежа, возвращаемого «<code>sys.exc_info()</code>» . Если программа не содержит подходящего обработчика, раскрутка стека выводится (в нормально оформленном виде) в стандартный поток ошибок, а если интерпретатор в интерактивном режиме, то она также доступна пользователю через «<code>sys.last_traceback</code>» .
Специальные атрибуты только для чтения: «<code>tb_next</code>» указывает следующий уровень в стеке (в сторону кадра, где произошло исключение) , или «<code>None</code>» , если нет следующего уровня; «<code>tb_frame</code>» указывает на кадр исполнения текущего уровня; «<code>tb_lineno</code>» дает номер строки, где произошло исключение; «<code>tb_lasti</code>» указывает точную инструкцию. Номер строки и последняя команда в раскрутке может отличаться от номера строки соответствующего объекта кадра, если исключение произошло в инструкции «<code>try</code>» не имеющей соответствующей ветви «<code>except</code>» , или с ветвью «<code>finally</code>» .
Объекты - срезы (извлечения, slices)
Объекты-срезы используются для хранения параметров для операции среза (которая может быть явно вызвана через метод "__getitem__()" ). Объект-срез также может быть создан встроенной функцией "slice()" .
Особые атрибуты только для чтения:
"start" - нижняя граница;
"stop" - верхняя граница;
"step" - значение шага;
все они по умолчанию имеют значение "None" . Эти атрибуты могут быть любого типа.
Объекты-срезы поддерживают один метод:
slice.indices(self, length)
Этот метод принимает один аргумент - целое число "length" и преобразовывает параметры среза (пропущенные, выходящие за границы (отрицательные или превышающие)) так, как они были бы преобразованы будучи применёнными (к любой) последовательности длины "length" (т. е. , например, граница среза, превышающая длину, заменяется на эту длину). Именно это преобразование производится при обычной записи срезов. Этот метод возвращает кортеж из 3 целых чисел, являющихся соответственно параметрами "start", "stop", "step" .
Статические методы
Объекты статических методов обеспечивают способ предотвращения преобразования функциональных объектов в объекты методов, описанные выше. Объекты статических методов могут быть посредниками ("обертками") для любых других объектов, обычно для определяемых пользователем объектов методов. Когда объект статического метода запрашивается из класса или экземпляра класса, то фактически возвращается объект, к которому тот является посредником (т.е. "обёрнутый объект"), если он в свою очередь не подлежит дальнейшей трансформации. Объекты статических методов сами не являются исполнимыми, хотя те объекты, к которым они явлвются посредниками - обычно явлвются. Объекты статических методов создаются при помощи встроенного конструктора "staticmethod()" .
Объекты методов классов
Объект метода класса, как и объект статического метода, является посредником к другому объекту, изменяющим способ, которым этот объект извлекается из классов и экземпляров класса. Поведение объектов метода класса при таком доступе описано выше, в разделе "Определяемые пользователем методы". Объекты методов классов создаются при помощи встроенного конструктора "classmethod()" .
3.3. Имена спецальных методов
Класс может реализовывать определенные операции, которые вызываются при использовании специального синтаксиса (например, арифметические операции или индексаця и срезы), путем определения методов со специальными именами. Это Питоновский подход к переопределению операторов, позволяющему классам определять их собственное поведение по отношению к операторам языка. Например, если класс определяет метод под названием "__getitem__()" и "x" экземпляр этого класса, то "x[i]" приблизительно равно "type(x).__getitem__(x, i)". За исключением тех случаев, где это особо оговорено – попытки исполнять операции вызывают исключение, если не определено соответствующего метода (обычно "AttributeError" или "TypeError" ) .
При реализации класса, который эмулирует любой встроенный тип, важно, что эмуляция должна быть реализована только в той степени, в какой это имеет значение для моделируемого объекта. Например, некоторые последовательности могут хорошо работать с извлечением отдельных элементов, но срезы могут не иметь смысла. (Одним из примеров этого является интерфейс "NodeList" в "W3C’s Document Object Model".)
3.3.1. Основные средства настройки классов
«<code>object.__new__(cls[, ...])</code>»
Вызывается для создания нового экземпляра класса «<code>cls</code>» . «<code>__new__()</code>» – это статический метод (специальный, создаваемый автоматически) , который принимает в качестве первого аргумента класс, экземпляр которого требуется вернуть. Остальные аргументы такие же, какие передаются конструктору этого же объекта (в выражении «<code>cls()</code>» ) . «<code>__new__()</code>» должен возвращать новый экземпляр объекта ( обычно экземпляр класса «<code>cls</code>» ) .
Обычно применяется для создания нового экземпляра класса через вызов метода «<code>__new__()</code>» у «суперкласса» данного класса, вызывая «<code>super(currentclass, cls).__new__(cls[, ...])</code>» с соответствующими аргументами, и затем модифицируя (при необходимости) новосозданный экземпляр перед его возвращением.
Если «<code>__new__()</code>» возвращает экземпляр класса «<code>cls</code>» , то будет вызван метод «<code>__init__()</code>» этого нового экземпляра : «<code>__init__(self[, ...])</code>» , где «<code>self</code>» – это данный новый экземпляр, а остальные аргументы – именно те, которые были переданы в «<code>__new__()</code>» .
Если «<code>__new__()</code>» не возвращает экземпляр класса «<code>cls</code>» , то метод «<code>__init__()</code>» нового экземпляра не будет вызываться.
«<code>__new__()</code>» главным образом нужен для того, чтобы дать возможность классам, производным от неизменяемых типов (таких как “int” , “str” , “tuple”) , настраивать создание экземпляров. Он к тому же часто переопределяется в метаклассах для настройки создания класса.
object.__init__(self[, ...])
Этот метод вызывается при создании соответствующего экземпляра. Его аргументами становятся те, которые были переданы выражению конструктору класса. Если в базовом классе определён метод "__init__()" , то метод "__init__()" производного класса (если определён) должен явно вызывать его, чтобы гарантировать правильную инициализацию части экземпляра, соответствующей базовому классу ( например : "BaseClass.__init__(self, [args...])" ) . Для конструкторов есть особый запрет - они не должны возвращать какого-либо значения - иначе вызывается ошибка "TypeError" .
object.__del__(self)
Этот метод (называемый также деструктор) вызывается, когда данный экземпляр должен быть уничтожен. Если в базовом классе определён метод "__del__()" , то метод "__del__()" производного класса (если определён) должен явно вызывать его, чтобы гарантировать правильное удаление части экземпляра, соответствующей базовому классу. Заметьте, что метод "__del__()" может (хотя это не рекомендуется) отложить удаление экземпляра, создав новую ссылку на него. Он может быть вызван потом, когда будет удалена эта новая ссылка. Не гарантируется, что методы "__del__()" будут вызваны для объектов, существующих на момент закрытия интерпретатора.
Замечание
«del x» лишь уменьшает на 1 счётчик ссылок на «x» , а не вызывает напрямую «x.__del__()» , который вызывается только когда счётчик ссылок достигает ноля. Среди ситуаций, при которых счётчик ссылок на объект не может обнулиться, самыми обычными являются : циклические ссылки между объектами (например, список с двухсторонними связями, или древовидная структура данных с указателями на родителя и потомка) ; ссылка на объект в кадре стека функции, которая получила исключение (раскрутка стека, содержащаяся в «sys.exc_info()[2]» , имея ссылку на этот кадр стека, не даёт его уничтожить) ; или ссылка на объект в том кадре стека, в котором произошло необработанное исключение в интерактивном режиме (раскрутка стека, содержащаяся в «sys.last_traceback» , имея ссылку на этот кадр стека, не даёт его уничтожить) . Первая ситуация может быть исправлена только путем явного разрывания цикла, а две последние ситуации могут быть решены путём записи «None» в «sys.last_traceback» . Циклические ссылки, являющиеся «мусором» , детектируются если включена опция обнаружения циклов (по умолчанию включена) , но могут быть удалены только если не задействованы методы Питоновского уровня «__del__()» . Обратитесь к документации модуля «gc» за более подробной информацией о том, как детектор циклов обращается с методами «__del__()» , в частности описание значения у «garbage» .
Предостережение
По причине ненадёжной ситуации, в которой вызываются методы «__del__()» , исключения, возникающие при их исполнении, игнорируются, и вместо этого печатаются предупреждения в «sys.stderr» . Также, когда «__del__()» вызывается для удаления модуля (например, когда исполнение программы завершено) , глобальные переменные, на которые ссылается метод «__del__()» , могут уже быть удалены или в процессе удаления (например, отключение механизма импорта) . По этой причине методам «__del__()» следует производить самый минимум необходимого для поддержания ???????????? . Начиная с версии 1.5 , Питон гарантирует, что глобальные переменные, чьё имя начинается с одиночного подчёркивания, будут удалены из их модуля до удаления остальных глобальных переменных. Если нет других ссылок на такие глобальные переменные, то это может помочь убедиться, что импортированные модули ещё доступны в то время, когда вызывается метод «__del__()» .
object.__repr__(self)
Вызывается встроенной функцией «repr()» для вычисления «официального» текстового представления (текстовый объект) для исходного объекта. В тех случаях, когда это вообще возможно – это текст должен быть правильным выражением на Питоне, который, при его интерпретации, даст обратно объект с тем же значением (при условии такого же окружения) . А когда это не возможно – будет возвращён текст вида : <…полезное описание…> . Если в классе определён «__repr__()» , но не определён «__str__()» , то «__repr__()» используется также и вместо «__str__()» .
Это обычно используется для отладки, поэтому важно, чтобы это представление было информационно богатыми и недвусмысленным.
object.__str__(self)
Вызывается встроенной функцией «str()» и функцией «print()» для вычисления «неформального» текстового представления (текстовый объект) для исходного объекта. Отличается от «__repr()__» тем, что не обязан выдавать правильное выражение на Питоне, вместо этого может выдать более удобный или лаконичный текст.
object.__format__(self, format_spec)
Вызывается встроенной функцией «format()» для получения «форматированого» текстового представления (текстовый объект) для исходного объекта. Аргумент «format_spec» является строкой, содержащей описание требуемых опций форматирования. Интерпретация этого аргумента полагается на реализацию метода «__format__()» у соответствующего типа, хотя большинство классов будут перепоручать форматирование одному из встроенных типов, или использовать аналогичный синтаксис опций форматирования.
Описание стандарта синтаксиса форматирования смотрите в <a href="http://docs.python.org/py3k/library/string.html#formatspec">Format Specification Mini-Language</a>.
-
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
Это так называемые методы «расширенного сравнения» («rich comparison») . Соответствие между символами операторов и именами методов такое : «x<y» вызывает «x.__lt__(y)» , «x<=y» вызывает «x.__le__(y)» , «x==y» вызывает «x.__eq__(y)» , «x!=y» вызывает «x.__ne__(y)» , «x>y» вызывает «x.__gt__(y)» , «x>=y» вызывает «x.__ge__(y)» .
Метод расширенного сравнения может возвращать синглтон «NotImplemented» , если в нём не реализована операция сравнения для данной пары аргументов. По соглашению – в случае успешных сравнений возвращается «False» или «True» . Однако, эти методы могут возвращать любое значение – так что, если эти операторы сравнения используются там, где требуется логический (булев) результат (например условие инструкции «if» ) , то Питон применит «bool()» к этим значениям (чтобы привести их к булеву типу) .
Нет неявно подразумеваемых соотношений между операторами сравнения. Истинность «x==y» не означает, что «x!=y» ложно. Таким образом, определяя «__eq__()» , следует также определить «__ne__()» –только тогда операторы будут вести себя, как ожидалось. Смотрите в пункте о «__hash__()» некоторые важные замечания о создании хэшируемых объектов, которые поддерживают пользовательские операции сравнения и могут использоваться в качестве ключей словаря.
Для этих методов нету реализации автоматической замены порядка аргументов (когда левый аргумент не поддерживает данную операцию, а правый поддерживает) . Но, вместо этого можно воспользоваться тем, что «__lt__()» с «__gt__()» , «__le__()» с «__ge__()» , «__eq__()» с «__ne__()» являются противоположностями друг друга (попарно) .
Для аргументов расширенных сравнений никогда не производится приведение типов.
Об автоматической генерации операций сравнения на основе одной операции смотрите <a href="http://code.activestate.com/recipes/576529/"> Total Ordering recipe in the ASPN cookbook</a>.
object.__hash__(self)
Вызывается встроенной функцией «hash()» и для операций над членами хэшируемых коллекций, включая «набор» («set») , «фиксированный набор» («frozenset») и «словарь» («dict») . Метод «__hash__()» должен возвращать целое число. Единственным обязательным свойством является то, что равные объекты имеют одинаковое значение хэша. ……………
Если класс не определяет метод «__eq__()» , то он не должен определять метод «__hash__()» , а если он определяет «__eq__()» , но не определяет «__hash__()» , то его экземпляры не смогут быть использованы как элементы хэшируемых множеств. Если класс определяет изменяемые объекты и реализует метод «__eq__()» , то он не должен реализовывать «__hash__()» , поскольку реализация хэшируемых множеств требует, чтобы значение хэша ключей было неизменяемым (если значение хэша ключа объекта изменяется, то оно может оказаться не в своей группе хэшей («hash bucket») (и будет пропущено при поиске) ) .
Определяемые пользователем классы по умолчанию имеют методы «__eq__()» и «__hash__()» , из-за которых все объекты экземпляров этих классов являются неравными друг другу (они равны только сами себе) , а «x.__hash__()» возвращает «id(x)» .
Классы, которые наследуют метод «__hash__()» из родительского класса, но изменяют значение «__eq__()» так, что возвращаемое значение хэша уже теряет разумный смысл (например, переходя к концепции сравнения на основании значения вместо стандартного сравнения на основе уникальных идентификаторов) могут явным образом обозначить себя как нехэшируемые установив «__hash__ = None» в определении класса. Такое действие приведёт не только к тому, что экземпляры данного класса будут вызывать соответствующее исключение «TypeError» , когда программа попытается получить их значение хэша, но и к тому, что экземпляры будут правильно идентифицированы как нехэшируемые при проверке «isinstance(obj, collections.Hashable)» (в отличие от классов, которые определили собственный «__hash__()» , явно вызывающий исключение «TypeError» ) .
Если классу, переопределившему «__eq__()» нужно оставить реализацию «__hash__()» из родительского класса, то это нужно обязательно делать явным образом : «__hash__ = .__hash__» . Иначе наследование «__hash__()» будет блокировано, так же, как если бы «__hash__» был явно установлен в «None» .
object.__bool__(self)
Вызывается для реализации проверки значения на истинность и встроенной операции «bool()» . Должен возвращать «False» или «True» . Если этот метод не определён, то вызывается «__len__()» , если тот определён, и, если результат ненулевой, то данный объект считается значащим «True» . Если класс не определяет ни «__len__()» , ни «__bool__()» , то его экземпляры считаются значащими «True» .
3.3.2. Настройка (обработка) доступа к атрибутам
Следующие методы могут быть определены для настройки доступа (чтение, запись (назначение) , удаление) к атрибутам экземпляров класса.
object.__getattr__(self, name)
Вызывается, когда искомый атрибут не найден в соответствующих местах (тоесть, он не является атрибутом экземпляра и не найден в дереве классов данного экземпляра) . «name» – имя атрибута. Этот метод должен возвращать значение (вычисленное) атрибута, или инициировать исключение «AttributeError» .
Заметьте, что если атрибут найден обычным способом, то «__getattr__()» не вызывается. (Несимметричность в этом смысле между «__getattr__()» и «__setattr__()» создана намеренно. ) Это сделано и в целях эффективности и из-за того, что иначе у «__getattr__()» не было бы никакой возможности доступа к другим атрибутам экземпляра. Кстати, по крайней мере для переменных экземпляра вы можете имитировать тотальный контроль за счёт непомещения их в словарь атрибутов данного экземпляра (а храня их в другом объекте) . Смотрите метод «__getattribute__()» ниже, предоставляющий способ действительно полностью контролировать доступ к атрибутам.
object.__getattribute__(self, name)
Вызывается безусловно (всегда, когда определён) для реализации доступа к атрибутам экземпляров данного класса. Если в классе также определён «__getattr__()» , то он не будет вызван, если только «__getattribute__()» не вызовет его явно или не инициирует исключение «AttributeError» . Этот метод нужен, чтобы возвращать значение (вычисленное) атрибута, или инициировать исключение «AttributeError» . Чтобы при доступе к нужным атрибутам избежать бесконечной рекурсии, в реализации этого метода всегда нужно вызывать метод базового класса с тем же именем, например, «object.__getattribute__(self, name)» (вместо «self.name») .
Замечание
Этот метод всё же может быть обойдён обращением к специальным методам в результате явного обращения с помощью специального синтаксиса языка или встроенных функций. Смотрите «Обращение к специальным методам» .
object.__setattr__(self, name, value)
Вызывается при попытке записи (назначения) атрибута. Он вызывается вместо стандартного механизма (тоесть, вместо сохранения значения в словаре экземпляра) . «name» – имя атрибута, «value» – значение, которое нужно под этим именем сохранить (назначить) .
Если «__setattr__()» хочет получить доступ к атрибуту экземпляра, ему следует вызывать метод базового класса с тем же именем, например, «object.__setattr__(self, name, value)» (вместо «self.name») .
object.__delattr__(self, name)
Подобен «__setattr__()» , только вместо назначения – удаляет атрибут. Реализовывать его следует только если «del obj.name» должен иметь какой-то специальный смысл для данного объекта.
object.__dir__(self)
Вызывается, когда вызывается «dir()» с аргументом «object» . Должен возвращаться список.
3.3.2.1. Реализация дескрипторов
Следующие методы служат для “перехвата” обращения к объекту, содержащему их. Но есть принципиальные ограничения. Эти методы задействуются только у тех объектов, у которых они определены в их классе (такой класс называется “описатель” ) , и которые (объекты) являются атрибутом другого класса (присутствуют в словаре атрибутов этого класса или его родительских классов) (такой класс называется “владелец” ) . В примерах, данных ниже, “данный атрибут” подразумевает тот атрибут, чьё имя является ключом словаря «__dict__» класса – владельца.
object.__get__(self, instance, owner)
Вызывается для получения «данного атрибута» класса-владельца (доступ к атрибуту класса) или экземпляра класса-владельца (доступ к атрибуту экземпляра) . Аргумент «owner» всегда – класс-владелец, а аргумент «instance» – это тот экземпляр, через который «данный атрибут» был получен или «None» , когда «данный атрибут» был получен через «владельца» . Этот метод должен возвращать значение «данного атрибута» (вычисленное) , или инициировать исключение «AttributeError» .
object.__set__(self, instance, value)
Вызывается для установки (записи) значения «value» для «данного атрибута» в экземпляре «instance» класса-владельца.
object.__delete__(self, instance)
Вызывается для удаления «данного атрибута» в экземпляре «instance» класса-владельца.
3.3.2.2. Вызов дескрипторов
Дескриптором является такой атрибут, который при этом является объектом, в классе которого определён хотябы один из методов: «__get__()» , «__set__()» и «__delete__()» .
Обычно эффект доступа к атрибутам заключается в чтении, записи или удалении их из словаря объекта. Например, поиск «a.x» происходит в такой последовательности : «a.__dict__['x']» , затем «type(a).__dict__['x']» и далее в базовых классах класса «type(a)» , исключая метаклассы.
Но, если значением искомого атрибута является объект, в котором определён один из дескрипторных методов, то Питон может обойти обычное поведение и вызвать вместо этого дескрипторный метод. На каком этапе последовательности поиска атрибута это произойдёт – зависит от того, какие дескрипторные методы были определены, и как они были вызваны.
Отправной точкой для вызова дескриптора является значение «<code>a.x</code>» : то как собираются аргументы для этого вызова – зависит от «<code>a</code>» :
Прямой вызов
Простейшим и наименее обычным является прямой вызов пользовательским кодом дескрипторного метода : «x.__get__(a)» .
Связывание (подстановка) через экземпляр
При связывании через объект-экземпляр «a» : «a.x» преобразуется в вызов «type(a).__dict__['x'].__get__(a, type(a))» .
Связывание (подстановка) через класс
При связывании через класс «A» : «A.x» преобразуется в вызов «A.__dict__['x'].__get__(None, A)» .
Связывание (подстановка) через базовый класс
Если «<code>a</code>» является экземпляром “надкласса” , то при связывании через «<code>super(B, obj).m()</code>» используется «<code>obj.__class__.__mro__</code>» чтобы найти такой класс «<code>A</code>» , который является непосредственным базовым классом для «<code>B</code>», и затем вызывается «<code>A.__dict__['m'].__get__(obj, A)</code>» .
Например привязки, приоритет описания обращения зависит от того, какие описательские
методы определены. Как правило, описания данных определяют как get__ __ () и __ set__ (), в то время как среди нефактических описаний данных есть только get__ __ () метод. Описания данных всегда отменяют переопределения в словаре экземпляра. И наоборот, нефактические описания данных могут быть переопределены с помощью экземпляров.
Описание может определять любую комбинацию __get__(), __set__() и __delete__(). Если оно не определяет __get__(), то обращение к атрибуту даже на примере вернет описание самого объекта. Если описание определяет __set__() и/или __delete__(), то это описание данных, если оно не определяет ни того, ни другого, то это нефактическое описание.
Методы Python (в том числе staticmethod() и classmethod() ) реализованы в виде нефактических описаний. Соответственно, экземпляры могут переопределять и аннулировать методы. Это позволяет отдельным экземплярам приобрести свойства, которые отличаются от свойств других экземпляров того же класса.
Функция присваивания реализована в виде описания данных. Соответственно, экземпляры не могут переопределять свойства наследования.
3.3.2.3. «__slots__»
По умолчанию экземпляры классов имеют словарь для хранения атрибутов. Это расходует много места для объектов, имеющих мало своих переменных. Расход места может стать острым, при создании большого количества экземпляров.
Это стандартное поведение можно отменить, определив «__slots__» в определении класса. «__slots__» получает последовательность переменных экземпляра и резервирует в каждом экземпляре только необходимое для хранения значений всех его переменных количество места. Место экономится, поскольку не создаётся «__dict__» для каждого экземпляра.
object.__slots__
Этой переменной класса можно назначить строку, итерируемый объект или последовательность строк с именами переменных, используемых экземплярами. В случае объявления его в классе, «__slots__» резервирует место для объявленных переменных и отменяет автоматическое создание «__dict__» и «__weakref__» для каждого экземпляра.
3.3.2.3.1. Замечания по использованию «__slots__»
При наследовании от класса без «__slots__», атрибут «__dict__» этого класса будет всегда доступным, поэтому определение «__slots__» в подклассах бесполезно.
Без переменной __dict__ экземплярам не могут быть назначены новые переменные, не перечисленные в определении __slots__. Попытки назначений не перечисленных имен переменных вызывают ошибку AttributeError. Если желательно динамическое назначение новых переменных, добавьте '__dict__' в последовательность строк в определении __slots__.
Без переменной «<code>__weakref__</code>» у каждого экземпляра – классы, в которых определён «<code>__slots__</code>» – не поддерживают «слабые» ссылки на свои экземпляры. Если поддержка слабых ссылок нужна, то к последовательности строк в объявлении «<code>__slots__</code>» добавьте «<code>”__weakref__”</code>» .
«<code>__slots__</code>» реализованы на уровне соответствующего класса посредством создания дескрипторов (смотрите «Реализация дескрипторов») для каждого имени переменной. В результате атрибуты класса не могут быть использованы для установки значений по-умолчанию для переменных у экземпляров, определённых посредством «<code>__slots__</code>» – иначе атрибуты этих классов могли бы переписать назначение этих дескрипторов.
Эффект объявления «<code>__slots__</code>» распространяется только на тот класс, в котором этот атрибут определён. Таким образом : подклассы будут иметь атрибут «<code>__dict__</code>» , если сами также не определят «<code>__slots__</code>» (который должен содержать имена только дополнительных “слотов” ) .
Если класс определяет “слот” , который определён и в базовом классе, то та переменная экземпляра, которая определена “слотом” базового класса, будет недоступна (за исключением явного получения дескриптора через базовый класс) . Это делает неопределённым значение программы. В будущем для предотвращения этого может быть добавлена какая-либо проверка.
Непустой атрибут «<code>__slots__</code>» не действует для классов, произведённых от встроенных типов “переменной длинны” , таких как «<code>int</code>» , «<code>str</code>» и «<code>tuple</code>» .
Любой перебираемый (“итерируемый”) объект, кроме текста – может быть назначен атрибуту «<code>__slots__</code>» . Отображения тоже могут быть использованы, однако, в будущем им может быть придан специальный смысл.
Назначение атрибуту «<code>__class__</code>» работает, только если оба класса имеют один и тот же «<code>__slots__</code>» .
3.3.3. Управление созданием классов
По умолчанию классы создаются с использованием «type(name, bases, dict)» . Определение класса «считывается» в отдельное пространство имён, и получившемуся результату назначается соответствующее имя класса.
Когда описание данного класса считывается, если передан исполнимый аргумент под ключевым словом «metaclass» после базовых классов в определении класса, то этот исполнимый объект будет вызван вместо «type()» . Если переданы и другие именованные аргументы, то они также будут переданы этому метаклассу. Это позволяет писать классы или функции, которые отслеживают или изменяют процесс создания класса :
Модифицируя словарь данного класса перед тем, как данный класс будет создан.
Возвращая экземпляр другого класса, по сути исполняя роль функций-фабрик.
Эти шаги должны быть исполнены в методе «__new__()» данного метакласса – затем из этого метода может быть вызван «type.__new__()» для создания класса с другими свойствами. Следующий пример добавляет новый элемент к словарю данного класса перед созданием данного класса :
<code>class metacls(type):
def __new__(mcs, name, bases, dict):
dict['foo'] = 'metacls was here'
return type.__new__(mcs, name, bases, dict) </code>
Конечно, вы можете ещё и переопределять другие методы класса (или добавлять новые) . Например, определение метода «__call__()» позволяет настроить то, как ведёт себя данный класс при вызове, например, чтобы он не каждый раз создавал новый экземпляр.
Если у данного класса есть атрибут «<code>__prepare__()</code>» (обычно реализованный как класс или статический метод) , то он вызывается с именем данного класса и с кортежем его базовых классов в качестве аргументов – до исполнения (интерпретации) “тела” данного класса. Результатом должен быть объект, поддерживающий интерфейс отображения, который будет содержать область имён данного класса. По-умолчанию – это простой словарь. Это может использоваться, например, для запоминания (в возвращаемом упорядоченном словаре) того порядка, в котором атрибуты данного класса были объявлены.
Соответствующий метакласс определяется следующей последовательностью правил :
Если аргумент под именем «metaclass» передан с базовыми классами, то используется он.
Иначе, если есть хотя бы один базовый класс, то используются его метаклассы.
Иначе – используется метакласс по умолчанию («type») .
Возможные применения для метаклассов неограничены. Наиболее разработаны следующие : логирование, проверка интерфейса, автоматическое делегирование, автоматическое создание свойств, посредники, среды исполнения, и т. д. .
Далее дан пример метакласса, использующего «collections.OrderedDict» для запоминания порядка, в котором члены класса были определены :
<code>class OrderedClass(type):<br />
<br />
@classmethod<br />
def __prepare__(metacls, name, bases, **kwds):<br />
return collections.OrderedDict()<br />
<br />
def __new__(cls, name, bases, classdict):<br />
result = type.__new__(cls, name, bases, dict(classdict))<br />
result.members = tuple(classdict)<br />
return result<br />
<br />
class A(metaclass=OrderedClass):<br />
def one(self): pass<br />
def two(self): pass<br />
def three(self): pass<br />
def four(self): pass<br />
<br />
>>> A.members<br />
('__module__', 'one', 'two', 'three', 'four')</code>
Когда происходит переход к исполнению определения класса «A» , то этот процесс начинается с вызова из метакласса метода «__prepare__()» , который возвращает пустой объект «collections.OrderedDict» . Это отображение записывает методы и атрибуты класса «A» , как если бы они были определены внутри тела этого класса. Когда эти определения исполнены – данный упорядоченый словарь полностью заполняется, и метод «__new__()» метакласса вызывается. И последний создаёт новый тип и сохраняет ключи упорядоченого словаря в атрибуте «members» .
3.3.4. Эмулирование исполнимых объектов
<code>object.__call__(self[, args...])</code>
Вызывается, когда данный экземпляр вызывается как функция, если этот метод определён. «x(arg1, arg2, ...)» является краткой формой для «x.__call__(arg1, arg2, ...)» .
3.3.5. Эмулирование контейнерных типов
-
Следующие методы могут быть определены для реализации объектов-контейнеров. Контейнеры – это обычно последовательности (как списки или кортежи) или отображения (как словари) , но также могут быть реализованы другие виды. Первая группа следующих далее методов используется для эмуляции как последовательностей, так и отображений – разница в том, что для последовательностей допустимые ключи должны быть целым числом «<code>k</code>» в диапазоне «<code>0 <= k < N</code>» , где «<code>N</code>» равно длине данной последовательности, или быть объектом-срезом (который определяет диапазон элементов) . Также рекомендуется, чтобы отображения предоставляли методы : «<code>keys()</code>» , «<code>values()</code>» , «<code>items()</code>» , «<code>get()</code>» , «<code>clear()</code>» , «<code>setdefault()</code>» , «<code>pop()</code>» , «<code>popitem()</code>» , «<code>copy()</code>» и «<code>update()</code>» , дающие тот же эффект, что и в стандартных Питоновских словарях. Модуль «<code>collections</code>» предоставляет абстрактный базовый класс «<code>MutableMapping</code>» , облегчающий создание этих методов на основе базового набора из : «<code>__getitem__()</code>» , «<code>__setitem__()</code>» , «<code>__delitem__()</code>» и «<code>keys()</code>» . Изменяемые последовательности могут предоставлять методы : «<code>append()</code>» , «<code>count()</code>» , «<code>index()</code>» , «<code>extend()</code>» , «<code>insert()</code>» , «<code>pop()</code>» , «<code>remove()</code>» , «<code>reverse()</code>» и «<code>sort()</code>» – как у обычных Питоновских списков. И, наконец, типы-последовательности могут реализовать сложение (тоесть конкатенацию) и умножение (тоесть повтор) – через определение методов : «<code>__add__()</code>» , «<code>__radd__()</code>» , «<code>__iadd__()</code>» , «<code>__mul__()</code>» , «<code>__rmul__()</code>» и «<code>__imul__()</code>» (их описание – ниже) – эти типы не должны определять другие числовые операции. Рекомендуется и в отображениях и в последовательностях обеспечивать метод «<code>__contains__()</code>» , который был бы эффективной реализацией оператора «<code>in</code>» . Для отображений – «<code>in</code>» должен искать в ключах этого отображения, а для последовательностей – в значениях. Кроме того, рекомендуется для отображений и последовательностей реализовывать метод «<code>__iter__()</code>» для эффективного перебора элементов в этом контейнере. Для отображений – «<code>__iter__()</code>» должен быть то же, что и «<code>keys()</code>» , а для последовательностей этот метод должен перебирать значения.
<code>object.__len__(self)</code>
Вызывается для реализации встроенной функции «len()» . Этот метод должен возвращать длину данного объекта в виде целого значения >= 0 . Кроме этого, объект, в котором не определён метод «__bool__()» и чей метод «__len__()» возвращает ноль – считается ложью в контексте булевых операций.
Примечание
Замечание : Срезы производятся исключительно следующими тремя методами. Вызов вроде :
<code>a[1:2] = b</code>
преобразуется в :
<code>a[slice(1, 2, None)] = b</code>
и так далее. Отсутствующие параметры среза всегда заполняются значениями «None» .
<code>object.__getitem__(self, key)</code>
Вызывается для реализации вычисления (получения) «self[key]» . Для типов-последовательностей – допустимые ключи должны быть целыми числами или объектами-срезами. Заметьте, что особая интерпретация негативных индексов (если данный класс желает эмулировать тип-последовательность) распространяется и на метод «__getitem__()» . Если «key» не подходящего типа, то может инициироваться «TypeError» , а если значение за пределами набора индексов данной последовательности (вследствие какой-либо оригинальной интерпретации негативных значений) – то должно инициироваться «IndexError» . Для отображающих типов, если «key» отсутствует (не в контейнере) – должно инициироваться «KeyError» .
Замечание : циклы «for» ожидают, что для недопустимых индексов будет инициировано «IndexError» , что нужно для правильного определения конца последовательности.
<code>object.__setitem__(self, key, value)</code>
Вызывается для реализации назначения для «self[key]» . То же замечание об отрицательных индексах, что и для «__getitem__()» . Этот метод должен быть реализован для отображений – только если эти объекты поддерживают изменение значений ключей, или если могут добавляться новые ключи, или для последовательностей, если элементы могут быть заменены. Для неправильных значений «key» исключения должны инициироваться также, как и для «__getitem__()» .
<code>object.__delitem__(self, key)</code>
Вызывается для реализации удаления «self[key]» . То же замечание об отрицательных индексах, что и для «__getitem__()» . Этот метод должен быть реализован для отображений – только если эти объекты поддерживают удаление ключей, или для последовательностей, если элементы могут быть удалены из этой последовательности. Для неправильных значений «key» исключения должны инициироваться также, как и для «__getitem__()» .
<code>object.__iter__(self)</code>
Этот метод у данного объекта-контейнера вызывается, когда нужен итератор для данного объекта. Этот метод должен возвращать новый объект-итератор, который будет перебирать все объекты в этом объекте-контейнере. Для отображений он должен перебирать ключи, и также должен быть доступен в качестве метода «keys()» .
Сами объекты-итераторы тоже должны реализовывать этот метод – для того, чтобы возвращать самих себя. Дополнительную информацию об объектах-итераторах смотрите в «Итерируемые типы» .
<code>object.__reversed__(self)</code>
Вызывается (если имеется) встроенной функцией «<code>reversed()</code>» для реализации перебора в обратном порядке. Этот метод должен возвращать новый объект-итератор, который будет перебирать в обратном порядке все объекты в данном объекте-контейнере.
Если метод «<code>__reversed__()</code>» не предоставлен, то встроенная функция «<code>reversed()</code>» будет использовать рассматриваемый в данном параграфе протокол последовательностей (а именно : «<code>__len__()</code>» и «<code>__getitem__()</code>» ) . Объекты, поддерживающие данный протокол должны предоставлять «<code>__reversed__()</code>» , только если они могут обеспечить более эффективную реализацию, чем предлагает «<code>reversed()</code>» .
Операторы проверки вхождения ( «<code>in</code>» и «<code>not in</code>» ) обычно реализуются через перебор последовательности. Однако, контейнерные объекты могут предоставлять перечисленные ниже специальные методы с более эффективной реализацией, при этом не обязательно, чтобы объекты были последовательностями.
<code>object.__contains__(self, item)</code>
Вызывается для реализации операторов проверки членства. Должен возвращать «True» , если «<code>item</code>» находится в «<code>self</code>» , иначе – «False» . Для объектов-отображений при этом подразумеваются ключи, а не значения или пары ключ–значение.
Для объектов, в которых не определён «<code>__contains__()</code>» , проверка членства сначала пытается перебирать с помощью «<code>__iter__()</code>» , затем используя устаревший подход – с помощью «<code>__getitem__()</code>» ( <a href="http://docs.python.org/py3k/reference/expressions.html#membership-test-details">подробнее в соответствующем разделе</a> ) .
3.3.7. Эмулирование числовых типов
Следующие методы могут быть определены для эмулирования числовых объектов. Методы, соответствующие операциям, не поддерживаемым данным конкретным видом реализуемого числа (например, побитовые операции для не целых чисел) – не следует определять.
object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__truediv__(self, other)
object.__floordiv__(self, other)
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)
Данные методы вызываются для реализации двухоперандных (“двоичных”) операций ( «<code>+</code>», «<code>-</code>», «<code>*</code>», «<code>/</code>», «<code>//</code>», «<code>%</code>», «<code>divmod()</code>», «<code>pow()</code>», «<code>**</code>», «<code><<</code>», «<code>>></code>», «<code>&</code>», «<code>^</code>», «<code>|</code>» ) . Например, для вычисления выражения «<code>x + y</code>» , где «<code>x</code>» является экземпляром класса, имеющего метод «<code>__add__()</code>» – вызывается метод «<code>x.__add__(y)</code>» . Метод «<code>__divmod__()</code>» должен быть эквивалентным использованию методов «<code>__floordiv__()</code>» и «<code>__mod__()</code>» , но он не должен соответствовать «<code>__truediv__()</code>» . Заметьте, что «<code>__pow__()</code>» должен быть определён принимающим необязательный третий аргумент, если должна поддерживаться трёхоперандная версия «<code>pow()</code>» .
Если какой-либо из указанных выше методов не поддерживает операцию над предоставленными аргументами – он должен вернуть значение «<code>NotImplemented</code>» .
object.__radd__(self, other)
object.__rsub__(self, other)
object.__rmul__(self, other)
object.__rtruediv__(self, other)
object.__rfloordiv__(self, other)
object.__rmod__(self, other)
object.__rdivmod__(self, other)
object.__rpow__(self, other)
object.__rlshift__(self, other)
object.__rrshift__(self, other)
object.__rand__(self, other)
object.__rxor__(self, other)
object.__ror__(self, other)
Данные методы вызываются для реализации двухоперандных (“двоичных”) операций ( «<code>+</code>», «<code>-</code>», «<code>*</code>», «<code>/</code>», «<code>//</code>», «<code>%</code>», «<code>divmod()</code>», «<code>pow()</code>», «<code>**</code>», «<code><<</code>», «<code>>></code>», «<code>&</code>», «<code>^</code>», «<code>|</code>» ) с обратным порядком операндов . Эти функции вызываются, только если первый (левый) операнд не поддерживает соответствующую операцию, а операнды разных типов. (Для операндов одинакового типа – подразумевается, что если метод для “прямого” порядка (например, «<code>__add__()</code>» ) непримени́м, то данная операция вообще не поддерживается – поэтому “обратная” операция и не вызывается. ) Например : при вычислении выражения «<code>x - y</code>» , где «<code>y</code>» является экземпляром класса, имеющего метод «<code>__rsub__()</code>» – вызывается «<code>y.__rsub__(x)</code>» , если «<code>x.__sub__(y)</code>» возвращает значение «<code>NotImplemented</code>» .
Заметьте, что трёхоперандное «<code>pow()</code>» не будет пытаться вызвать «<code>__rpow__()</code>» (соответствующие правила приведения (перехода) были бы слишком сложны) .
-
Замечание : Если тип правого операнда является подклассом класса левого операнда, и тот подкласс предоставляет для той же операции метод с обратным порядком операндов, то этот метод будет вызван до метода с прямым порядком у левого операнда. Такое поведение позволяет подклассам переопределять операции их предков.
object.__iadd__(self, other)
object.__isub__(self, other)
object.__imul__(self, other
object.__itruediv__(self, other)
object.__ifloordiv__(self, other)
object.__imod__(self, other)
object.__ipow__(self, other[, modulo])
object.__ilshift__(self, other)
object.__irshift__(self, other)
object.__iand__(self, other)
object.__ixor__(self, other)
object.__ior__(self, other)
Данные методы вызываются для реализации расширеных арифметических операций-назначений ( «<code>+=</code>», «<code>-=</code>», «<code>*=</code>», «<code>/=</code>», «<code>//=</code>», «<code>%=</code>», «<code>**=</code>», «<code><<=</code>», «<code>>>=</code>», «<code>&=</code>», «<code>^=</code>», «<code>|=</code>» ) . Эти методы должны пытаться выполнять операции “на месте” (изменяя «<code>self</code>») и возвращать результат (который может, но не обязан быть «<code>self</code>» ) . Если специальный метод не определён, то операция использует обычные арифметические методы. Например, для вычисления выражения «<code>x += y</code>» , где «<code>x</code>» является экземпляром класса, имеющего метод «<code>__iadd__()</code>» – вызывается «<code>x.__iadd__(y)</code>» . Если «<code>x</code>» является экземпляром класса, в котором не определён метод «<code>__iadd__()</code>» , то используются «<code>x.__add__(y)</code>» и «<code>y.__radd__(x)</code>» – как для вычисления «<code>x + y</code>» .
object.__neg__(self)
object.__pos__(self)
object.__abs__(self)
object.__invert__(self)
Данные методы вызываются для реализации однооперандных арифметических операций ( «<code>-</code>», «<code>+</code>», «<code> abs()</code>» и «<code>~</code>» ) .
object.__complex__(self)
object.__int__(self)
object.__float__(self)
object.__round__(self[, n])
Данные методы вызываются для реализации встроенных функций «<code>complex()</code>», «<code>int()</code>», «<code>float()</code>» и «<code>round()</code>» . Должны возвращать значение соответствующего типа.
object.__index__(self)
Данный метод вызывается для реализации функции «<code>operator.index()</code>» . Также вызывается, когда Питону требуется целочисленный объект (например в срезах; или во встроенных функциях : «<code>bin()</code>», «<code>hex()</code>» и «<code>oct()</code>» ) . Должен возвращать целое число.
3.3.7. «Менеджеры контекста» для инструкции «<code>with</code>»
«Менеджер контекста» – это объект, который задаёт контекст, который должен быть установлен при исполнении инструкции «<code>with</code>» . Такой менеджер контекста управляет входом, выходом, требуемым контекстом исполнения данного блока кода. Менеджеры контекста обычно вызываются через инструкцию «<code>with</code>» (описание в разделе «Инструкция with» ) , но также могут использоваться через явный вызов их методов.
Характерное применение менеджеров контекста включает : сохранение и восстановление глобального состояния, блокирование и разблокирование ресурсов, закрытие открытых файлов, и т.д. .
Дополнительную информацию смотрите в разделе «Типы менеджеров контекста» .
object.__enter__(self)
Входит в оперативный (существующий на стадии исполнения) контекст, относящийся к данному объекту. Инструкция «<code>with</code>» будет назначать (связывать) возвращаемое значение этого метода целям (именам) заявленным в ветви «<code>as</code>» , если таковая имеется.
object.__exit__(self, exc_type, exc_value, traceback)
Выходит из оперативного (существующего на стадии исполнения) контекста, относящегося к данному объекту. Указанные параметры определяют, какое именно исключение привело к выходу из данного контекста. Если выход из данного контекста происходит без исключения, то все три аргумента будут «<code>None</code>» .
Если дано исключение и данный метод собирается «подавить» это исключение (тоесть, не пропустить его дальше) , то он должен вернуть значение, эквивалентное «True» . Иначе : по выходу из этого метода будет продолжена нормальная обработка данного исключения.
Заметьте, что методы «<code>__exit__()</code>» не должны перевызывать переданные внутрь них исключения – это обязанность вызвавшего кода.
Смотрите также :
PEP 0343 – Инструкция «<code>with</code>»
Спецификация, разъяснения и примеры по инструкции «<code>with</code>» языка Питон.
3.3.8. Обращение к специальным методам
Для определяемых пользователем классов, работа явных вызовов специальных методов гарантирована, только если эти методы определены в словаре класса данного объекта, а не экземпляра. Такое поведение приводит к тому, что следующий код приводит к исключению :
<code>>>> class C(object):
... pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()</code>
Смысл в таком поведении заключается в том, что некоторые специальные методы, такие как «<code>__hash__()</code>» и «<code>__repr__()</code>» , реализованы во всех объектах, включая и объекты-типы. Если бы явное обращение к этим методам использовало стандартный процесс обращения, то они бы вызывали ошибку при применении к самому объекту-классу :
<code>>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument</code>
Неправильные попытки вызвать таким способом несвязанный метод класса иногда называют «путаница метаклассов» и справляются с этим, пропуская экземпляр при доступе к специальным методам :
<code>>>> type(1).__hash__(1) == hash(1)<br />True<br />>>> type(int).__hash__(int) == hash(int)<br />True</code>
В дополнение к пропуску любых атрибутов экземпляров с целью сохранения корректности – явный поиск специального метода, в общем случае, также пропускает метод «<code>__getattribute__()</code>» даже в метаклассе данного объекта :
<code>>>> class Meta(type):<br />
... def __getattribute__(*args):<br />
... print("Metaclass getattribute invoked")<br />
... return type.__getattribute__(*args)<br />
...<br />
>>> class C(object, metaclass=Meta):<br />
... def __len__(self):<br />
... return 10<br />
... def __getattribute__(*args):<br />
... print("Class getattribute invoked")<br />
... return object.__getattribute__(*args)<br />
...<br />
>>> c = C()<br />
>>> c.__len__() # Explicit lookup via instance<br />
Class getattribute invoked<br />
10<br />
>>> type(c).__len__(c) # Explicit lookup via type<br />
Metaclass getattribute invoked<br />
10<br />
>>> len(c) # Implicit lookup<br />
10</code>
Пропуск механизма «<code>__getattribute__()</code>» в такой манере даёт значительное ограничение в пользу оптимизации по скорости в интерпретаторе, незначительно жертвуя удобством в обращении со специальными методами (специальный метод должен быть установлен в самом объекте-классе для того, чтобы быть нормально вызванным интерпретатором) .
Сноски
[1] К фрагменту №4
В некоторых случаях, при выполнении определённых условий, возможно изменить тип объекта. В общем случае – это плохая практика, поскольку это может приводить к некоторым очень странным результатам при неосторожном обращении.
Сноски подставлены : [2] в фр. 222 ; [3] в фр. 329
Внимание! Этот перевод, возможно, ещё не готов.
Его статус: идёт перевод
Переведено на Нотабеноиде
http://notabenoid.org/book/5672/17129
Переводчики: Hittih, RedFox, galayko, alvadia3
Viktorianka, pu
Настройки
Готово:
