Лутц М. - Изучаем Python (1077325), страница 146
Текст из файла (страница 146)
Я полагаю, в действительности онн имели в виду, что классы в языке Ру$Ьоп работают совсем не так, как в других языках программирования. Что в действительности имеется в языке РуФЬоп, так это связанные и несвязанные методы с четкой семантикой— при обращении к методу через имя класса вы получаете несвязанный метод, который представляет собой особую разновидность функций. В языке РуФоп имеются атрибуты класса, но функции в классе ожидают получить экземпляр в виде аргумента.
Кроме того, в языке Ру$Ьоп уже имеются модули, которые играют роль инструмента разделения пространства имен, поэтому обычно не возникает необходимости упаковывать функции в классы, если они не реализуют функциональность объектов. Простые функции внутри модуля обычно способны решать большую часть задач, которые возлагаются на методы класса. Например, в первом фрагменте в этом разделе функция ргзпт!чоа1пвтапсев уже связана с классом, потому что располагается в том же самом модуле. Единственный недостаток этой функции состоит в том, что она имеет более широкую область видимости— весь модуль, а не класс.
На сегодняшний день существует еще одна возможность писать простые функции, связанные с классом. Начиная с версии РуФЬоп 2.2 имеется возможность создавать классы со статическими методами и с методами класса, ни один из которых не требует передачи экземпляра класса в виде аргумента. Чтобы определить такие методы, в классах необходимо вызывать встроенные функции втат!светлов и с1авваетлоб, как упоминалось в обсуждении классов нового стиля. Например: с1авв Мо1ты ОЕт !аЕ(П(ВЕ1(, х): № Обнчний метод экземпляра ргтпт ве1(, х Оет ваетп(х): № Статический иетодг экземпляр не передается рг!Ит х оет смети(с1в, х). № Метод класса: получает класс, но не экземпляр рг!пт с1в, х ваетп = в!а!!светлое(ваетп) светл = с1авваетпоо(спето) № Сделать зиетп статичнским методом № Сделать свети методом класса Обратите внимание, как две последние операции присваивания в этом фрагменте просто переприсваивают имена методов ваетл и саетл.
Атрибуты создаются и изменяются с помощью операции присваивания в инструкции с1авв, поэтому эти заключительные операции присваивания переопределяют инструкции бе(, выполненные ранее. Использование статических методов и методов класса 680 Глава 26. Дополнительные возможности классов С технической точки зрения, язык Руйтоп теперь поддерживает три разновидности методов классов: методы экземпляра, статические методы и методы класса. Методы экземпляра — это обычные (и используемые по умолчанию) методы, которые мы видели в этой книге. Для воздействия на объект экземпляра всегда следует вызывать методы экземпляра.
Когда методы вызываются через экземпляр, интерпретатор автоматически передает экземпляр в первом аргументе — когда метод вызывается через имя класса, экземпляр необходимо передавать методам вручную: »> оо) = ИЬ111() а Создать экземпляр »> ЬЬ).1ввтл(1) я Обычный вызов, через экземпляр < еатп,.ио11> тпвтапое...> 1 »> ио111. 1аеть(оь), 2) а Обычный вызов, через класс < еа1п,.ио11> тпвтапое.. > 2 Статические методы, напротив, вызываются без аргумента с экземпляром класса — их имена ограничены областью видимости класса, в котором они определяются и могут отыскиваться механизмом наследования. Главным образом они действуют как обычные функции, которые просто находятся внутри класса: »> ИЬ111.
ваетл(3) 3 »> оь).ваетп(4) 4 в Вызов статического негода, через иия клаооз а Вызов статического иетода, через экзеипляр Мелтодьс класса похожи на них, но интерпретатор автоматически передает методам класса сам класс (а не экземпляр) в первом аргументе: »> Ио111.оавтл(5) ватп . Ио1Ы 5 »> ЬЬ).светл(Б) аатп .Ио1(1 6 а Вызов метода класса, через иия класса а Вызов метода класса, через экзеипляр Статические методы и методы класса являются новыми дополнительными особенностями языка с узко специализированным назначением, для описания которого у нас недостаточно места в этой книге.
Статические методы обычно используются для работы с атрибутами класса и управления информацией, которая касается всех экземпляров, созданных из класса. Например, чтобы вести подсчет количества созданных экземпляров класса (как в примере выше), можно было бы использовать статический метод, управляющий счетчиком, присоединенным к классу в виде атрибута. Такой счетчик не имеет ничего общего ни с одним из вкземпляров, поэтому было бы неудобно иметь методы, которые обслуживают его, вызываемые через экземпляр (тем более, что создание экземпляра для доступа к счетчику может изменить этот счетчик). Кроме того, близость статических методов к классу обеспечивает более естественное решение, чем ориентированные на класс функции за пределами класса.
Ниже приводится реализация статического метода, эквивалентного оригинальному примеру этого раздела: 681 Декораторы функций с1ввв Зрвп поа1пвтвпсев = О Ов( тпы (ве11). Зраа.поа1пвтвпсвв += 1 оег ргтптиоа1пвтвпсев() ргтпт "йоаьег от тпвтапсев ", Зрва пов1пвтвпсев рггптйоп1пвтапсев = втвттсввтьоо(рг1птйоа1пвтапсев) »> в = Зрва() »> Ь = Зрвв() »> с = Зрав() »> Зрвв.рг1пвйоа1пвтапсев() йопьег ог швтвпссв: 3 »> в.рг1птйоа1пвтвпсев() ИопЬег от тпвтвпсев: 3 По сравнению с простым перемещением рг1птйоп1пвтапсев за пределы класса, как описывалось ранее, эта версия требует дополнительный вызов функции всат(спетьос. При этом здесь область видимости имени функции ограничена классом (имя не будет вступать в конфликт с другими именами в модуле) и программный код перемещен туда, где он используется (внутрь инструкции с1авв).
Судите сами, является ли это чистым усовершенствованием или нет. В последних версиях Ру1)топ определение статических методов выполняется еще проще; следующий раздел описывает — как. Декораторы функций Прием с вызовом функции втат(спетьоО, описанный в предыдущем разделе, выглядит малопонятным для некоторых пользователей, поэтому была добавлена возможность, упрощающая эту операцию. Декораторы функций обеспечивают способ определять специальные режимы работы для функций, обертывая их дополнительным слоем логики, реализованной в виде других функций.
Декораторы функций представляют собой более универсальные инструменты: их удобно использовать для добавления самой разной логики к функциям, помимо статических методов. Например, их можно использовать для расширения функций программным кодом, выполняющим регистрацию вызовов этих функций, проверяющим типы передаваемых аргументов в процессе отладки и т. д. В некоторой степени декораторы функций напоминают шаблон проектирования делегирования, исследованный нами в главе 25, но их главная цель состоит в том, чтобы расширять определенные функции или методы, а не весь интерфейсобъекта. Язык Ру()топ предоставляет несколько встроенных декораторов функций для выполнения таких действий, как создание статических методов, но программисты также имеют возможность создавать свои собственные декораторы.
Несмотря на то, что они строго не привязаны 682 Глава 26. Дополнительные возможности классов к классам, тем не менее, пользовательские декораторы функций часто оформляются как классы, в которых сохраняется оригинальная функция наряду с другими данными, такими как информация о состоянии. Синтаксически декоратор функции — это разновидность объявления функции времени выполнения.
Декоратор функции записывается в строке непосредственно перед строкой с инструкцией Сет, которая определяет функцию или метод, и состоит из символа 9, за которым следует то, что называется метафункцией, — функция (или другой вызываемый объект), которая управляет другой функцией. В настоящее время статические методы, к примеру, могут быть оформлены в виде декораторов, как показано ниже: с1авв С: ввсасссвеслао оет весь(); С технической точки зрения, это объявление имеет тот же эффект, что и фрагмент ниже (передача функции декоратору и присваивание результата первоначальному имени функции): с1аьв С: оет весь(): весь = всасссвеслос(весь) а повторное лрисааиааиие ииаии В результате вызов метода по имени функции фактически будет приводить к вызову результата, полученному от декоратора втвС1светпоз.
Декоратор может возвращать объекты любого типа, поэтому данный прием позволяет декоратору вставлять дополнительный уровень логики, который будет запускаться при каждом вызове. Декоратор функции может возвращать как оригинальную функцию, так и новый объект, в котором хранится оригинальная функция, переданная декоратору, которая будет вызываться косвенно после того, как будет выполнен дополнительный слой логики.
Синтаксис декораторов поддерживает добавление нескольких слоев обертывающей логики к декорируемой функции или методу. В этом случае строка с декоратором выглядит следующим образом: ЕА ЮВ ВС сот с(): что эквивалентно следующему фрагменту: оет с(). т = А(В(С(т))) Здесь оригинальная функция проходит через три различных декоратора, а результат присваивается оригинальному имени. Напомню еще ввз Декораторы функций раз, что в результате всего этого, когда происходит обращение к ориги- нальному имени функции, вызываются три слоя логики, дополняю- щие оригинальную функцию.
Пример декоратора Ниже приводится пример декоратора, определяемого пользователем. Вспомните, как в главе 24 говорилось, что метод перегрузки оператора са11 реализует интерфейс вызова функций в экземплярах классов. В следующем примере этот метод используется в определении класса, который сохраняет декорируемую функцию в экземпляре и перехватывает вызовы по оригинальному имени. А так как это класс, кроме всего прочего в нем имеется возможность хранить информацию о состоянии (счетчик произведенных вызовов); с1авв тгасег; бег 1птт (вв1(, тцпс): ве1(.са11в = О вв1(.тцпс = тцпс Оет са11 (ве11, *агре): ве1(.са11в += 1 рг(пт 'са11 %в то 1(в' % (ве1г.са11в, ве1(.гцпс.