Саммерфилд - Программирование на Python 3 (1077331), страница 98
Текст из файла (страница 98)
3!й ного атрибута ае11. 1!зт. Восемь методов этого класса просто перекладывают свою работу иа методы частного атрибута. В качестве примера ниже приводится реализация методов Зогтесс!ат. с1еаг() и ЗогтеОЬ!вт. рор(): Ьат с1еаг(ае1Г): ае1Г. 1!а! = () Оет рср(ае!Г, тпаех=-!): гетигп ае1г. !тат.рор(!псах) В методе с1еаг() не делается ничего особенного, так как тип 1тз! не имеет соответствующего метода, но в методе рср() и еще в шести других методах, которые делегируются классом ЗогтеОЬ!зт, можно просто вызывать соответствующие методы класса 11з!.
Реализовать это можно с помощью декоратора классов эве1едате, реализацию которого можно найти в модуле 01!1, поставляемом с примерами к книге. Ниже приводится начало определения новой версии класса Зо гтеОЬ)ат: Фдт!1.де1едате(" 1!ат", ("рпр", " ае1!тее ", " дет!теа !тег ", " гечагаеа ", " 1еп ", " атг ")) с1ааа Загсам!!а!. Первый аргумент — это имя атрибута, которому будут делегированы операции, а второй аргумент — это последовательность из одного или более методов, которые должен будет реализовать декоратор ое1едасе(), чтобы избавить нас от этой рутины.
Этот подход используется при определении класса зогтеоь1ат, в файле Зогтеьиэтде1еда!е,ру, поэтому в нем отсутствует явная реализация перечисленных методов, но несмотря на это он полностью их поддерживает. Ниже приводится определение декоратора классов, который создает реализацию методов: пег Ое1едате(аттг!ьпте паве, эетьоо павел): пег аессгатог(с1а): поп1пса1 аттг!вита паве тг аттгтьпте паве нпагтанттп(" "): Улучшенные приемы объектно-ориентированного программирования 439 аттг1ьрте паве = " " т с1в.
паве + аттг1ьша паве тог паае !п пвтлпа пааев: ветаттг(с1в, паев, еча1("1аэааа вв1(, а, "Кч: "ве1(.(01.(1)(*а, *Кн)".тогаат( аттг1Ьрте паве, паве))) гетогп 01в гетчгп аесогатог Мы не можем использовать простой декоратор, т. к. декоратору требуется передавать аргументы, поэтому мы создали функцию, которая принимает наши аргументы и возвращает декоратор класса. Сам декоратор принимает единственный аргумент — класс (так же как декоратор функций принимает функцию или метод в виде единственного аргумента).
Мы вынуждены использовать инструкцию поп10са1, потому что вложенная функция обращается к аргументу атт г1Ьрте паве, находящемуся в области видимости внешней функции. А нам, в случае необходимости, нужна возможность корректировать имя атрибута, чтобы учесть приведение имен частных атрибутов. Декоратор обладает весьма простым поведением: он выполняет итерации по всем именам методов, которые были переданы функции ае1езате(), и для каждого из них создает новый метод, который устанавливается в качестве атрибута класса с заданным именем метода. Для создания каждого из делегируемых методов используется функция еча1( ), которая может использоваться для выполнения единственной инструкции 1авааа, воспроизводящей метод или функцию. Например, данный программный код воспроизводит метод рор(), как показано ниже: 1аэьаа ве1(, *а, * кчл ве1(, Богтепь1вт 1твт.ррр(*а, **ктт) Использование формы представления аргументов * и ** позволяет любым аргументам, даже относящимся к делегируемым методам, принимать требуемую форму списка аргументов.
Например, метод 1191. рор() принимает единственный аргумент — номер позиции в списке (или ни одного аргумента, в этом случае используется значение по умолчанию— номер позиции последнего элемента). Этот прием пригоден, даже когда методу передается неверное число аргументов или недопустимые значения, потому что в этом случае вызываемый метод класса 11вт возбудит соответствующее исключение.
Второй декоратор классов, который мы рассмотрим, такКаасс жЕ бУДЕт ПРИМЕНЯТЬСЯ К КЛаССУ, СОЗДаННОМУ В ГЛаВЕ 6. Кч,ауаррт Когда мы создавали класс Р022УВ001, мы упоминали, что стр. 291 при наличии реализации всего двух специальных методов 11 () и ез () (выполняющих операции < и ==), остальные методы сравнения будут генерироваться автоматически. Но тогда мы не показали полное начало определения класса: 440 Глава 8. Усовершенствованные приемы программирования ФЬЫ1.сьар1ете соарагтвопв с1авв Гпаауаоо!: Остальные четыре метода сравнивания определяются декоратором соар!ете созрагвтопз() класса.
Используя только реализацию поддержки оператора < (или < и ==), декоратор воспроизводит реализацию недостающих методов, используя следующие логические соотношения: х=ус: (х<уму<х) хиус> (х=у) х>у<оу<х х<ус> (у<х) хвуо> (х<у) Если декорируемый класс содержит реализацию операторов < и ==, декоратор будет испольэовать обе реализации; при этом декоратор перейдет к воспроизводению всех методов сравнивания через оператор <, если в классе присутствует реализация только этого оператора. (В действительности интерпретатор автоматически воспроизводит поддержку оператора >, если поддерживается оператор <; ! =, если поддерживается оператор == и >=, если поддерживается <=. Поэтому будет вполне достаточно реализовать всего три оператора: «, = и ==, а реализацию поддержки остальных операторов оставить за интерпретатором.
Однако при использовании декоратора класса этот минимум снижается до реализации единственного оператора <. Это, во-первых, очень удобно, а во-вторых, гарантирует, что все операторы сравнивания будут использовать одну и ту же непротиворечивую логику.) аег соар1ете сьараг!вопя(с1в): аввегт с1в. 11 гв пот оь)ест. 11 , ( "(0) аивт се(тле < апс шеа11у ==".тцгаат(с1в. паве )) тт с1в ец тв оЬ)ест. ец с1в, ец = 1ааааа ве1(, отяег: (пот (с1в. 11 (ве1(, с(лег) ьг с1в 11 (о(пег, ве1())) с1в. пе = 1ааьеа ве1(, о(пег: пот с1в. ец (ве1(, о(пег) с1в, цт = )аапза ве1(, о(пег; с1в. 11 (о(лег, ве1() с1в 1е = 1аеьоа ве!г, о(пег.
пот с1в, 1т (отпег, ве1() с1в, це = 1ааьса ве1(, о(пег: пьт с1в. 1т (зе1(, отпег) гетпгп с1з Одна из проблем, которую необходимо решить декоратору, состоит в том, что класс ЬЬ)ест, от которого в конечном счете происходят все остальные классы, определяет реализацию всех шести операторов сравнивания, возбуждающих исключение ТуреЕггог. Поэтому необходимо узнать, были ли переопределены методы поддержки операторов < и == (и, следовательно, узнать, можно ли их использовать). Это легко можно сделать, сравнив соответствующие специальные методы декорируемого класса с методами класса оЬ) ест. Если декорируемый класс не имеет собственной реализации поддержки оператора <, инструкция аввегт возбудит исключение, потому что 441 Улучшенные приемы объектно-ориентированного программирования поддержка этого оператора является минимально необходимой. Если в классе присутствует поддержка оператора ==, мы будем использовать существующую реализацию; в противном случае создадим ее.
После этого создаются остальные методы сравнивания, и возвращается класс, содержащий реализацию всех птести методов. Использование декораторов классов является, пожалуй, Матаклассы, самым простым и самым легким способом изменения стр 4я классов. Другой способ основан на использовании мета- классов — эта тема будет рассматриваться ниже в этой главе. Абстрактные базовые классы Абстрактным базовым классом (АЬэ(гас1 Вазе С1азэ, АВС) называется класс, который не может использоваться для создания объектов. Назначение таких классов состоит в определении интерфейсов, то есть в том, чтобы перечислить методы и свойства, которые должны быть реализованы в классах, наследующих абстрактный базовый класс.
Это удобно, так как можно использовать абстрактный базовый класс как своего рода договоренность — договоренность о том, что любые порожденные классы обеспечат реализацию методов и свойств, объявленных в абстрактном базовом классе.' Абстрактные классы — это классы, имеющие как минимум один абстрактный метод нли свойство. Объявления абстрактных методов могут не содержать их реализацию (то есть блок кода метода состоит из единственной инструкции раек, или, если необходимо предусмотреть обязательное переопределение метода в подклассах, из инструкции гаже Мот1зр1еаелтесЕггог()) или могут иметь действующую реализацию, которая может вызываться подклассами, например, предусматривающую обработку общих случаев. Кроме того, абстрактные классы могут содержать обычные (то есть неабстрактные) методы и свойства.
Классы, наследующие АВС, могут использоваться для создания экземпляров, только если они переопределяют все унаследованные абстрактные методы и абстрактные свойства. Дочерние классы с помощью функции зсрег() могут использовать версии абстрактных методов, имеющих действующую реализацию (даже если она состоит из единственной инструкции разя). Все неабстрактные методы нли свойства наследуются дочерними классами обычным образом. Любые абстрактные базовые классы должны использовать метакласс аЬс. АВЕМетз (из модуля аЬс) или метакласс от одного из его подклассов.
Метаклассы мы будем рассматривать немного ниже. Абстрактные базовые классы языка Ру1Ьоп описываются в РЕР 3119 (шшшруЯоп.огЯгуеигрерз/рер-3119), где вы также найдете очень полезные объяснения, которые стоит прочитать. Глава В. Усовершенствованные приемы программирования Таблица 8.3.Абстрактные базовые классы в модуле ~итЬегв АВС Наследует АР1 Примеры Мвврег сЬ)ест соар1ех, Сессаа1.0ессаа1, т(свт, (гарт!опв.Егастсоп, !пт ==, ! =, +, -, *, /, аЬв(), Ьсс1(), ссвр1вх(), ссп)врасе(); а так же свойства гва1 и савя Сокр1ех МввЬег ссвр1ех, Сес!|в1,Вес!аа1, Нсвт, тгвсс!спв.ргастссп, ьпт «,=, ==,! =, >ен >, +, -, *,/,//,%, аЬз(), Ьсс1(), соар1вх(), соп)азате(), С!хасСО, (1сат(), ватл.св>1(), ваСП.(1оог(), горло(), Сгвпс(); а также свойства геа1 и свар Яеа1 Ссвр1ех Сес!аа1.респаа1, т(свс, тгасспспв.егасспсп, !пт «,=, ==,!=, >ен >, +, -, °,/,//,%, аЬв(), Ьсс1(), ссар1ех(), ссп)свате(), С!апсо(), (1сат(), ваСЬ.се>1(), каСП.(1оог(), гсппо(), !гипс(); атакже свойства геа1, саар, пвавгатог и Серов>па!от Яат!спа1 Яев1 тгвсссспв.егассссп, спт Яассспа1 », -, З, ,(, аЬв(), Ьсс1(), ссвр1ех(), ссп)врете(), Сспасо(), (1оат(), вась.се>1(), аасп.(1осг(), рсн(), го- рло(), Сгвпс(); а также свойства геа1, саар, пваегатогн Свпсв!паСог 1птерга1 спт В языке Руз)соп имеется две группы абстрактных базовых классов.
Одна находится в модуле со11есС!опв, а другая — в модуле пьасегв. Они позволяют получать информацию об объекте; например, если у нас имеется переменная и, то мы можем определить, является она последовательностью — с помощью функции!з!пзсапсе(х, со11есссопв. Мрсаь)еВеарепсе) или целым числом — с помощью инструкции !в!патассе(х, псаЬе гв.
1птеВ га1). Это особенно удобно, учитывая динамическую типизацию в языке РуС)соп, когда нам не требуется знать точный тип объекта, а достаточно лишь убедиться, что он поддерживает операции, которые предполагается к нему применить. Числовые абстрактные классы и абстрактные классы коллекций перечислены в табл.