Лутц М. - Изучаем Python (1077325), страница 133
Текст из файла (страница 133)
га(Ы обрабатывает правостороннее сложение С технической точки зрения метод абб, который использовался в примерах выше, не поддерживает использование объектов экземпляров справа от оператора и. Чтобы реализовать поддержку таких выражений и тем самым обеспечить допустимость перестановки операндов, необходимо создать метод габб . Интерпретатор вызывает метод габб, только когда экземпляр вашего класса появляется справа от оператора +, а объект слева не является экземпляром вашего класса.
Во всех других случаях, когда объект появляется слева, вызывается метод абб »> с1авз Соееотег: бв1 спст (зе11, ча1): зе11.ча1 = ча1 бе1 абб (зе11, оспег): ог1пс 'абб', зв11.ча1, оспвг бе1 габб (ве11, оспег): рг1пС 'габб', ве11.ча1, ответ Вследствие этого, если вам необходимо обеспечить единое отображение во всех контекстах, лучше использовать метод герт .
Однако, определив оба метода, вы обеспечите поддержку вывода в различных контекстах. Например, перед конечным пользователем объект будет отображаться с помощью метода а(г,, а перед программистом будет выводиться информация более низкого уровня с помощью метода герт,. 620 Глава 24.
Подробнее о программировании классов »> х = Ссззстег(88) »> у = Ссззстег(99) »>х+1 Э збб . экзеипляр и не экзеипляр збб 88 1 »>1+у Э гэбб : не зкзеипляр + экзеипляр гзбб 99 1 »>х+у Э адб : зкзеипляр + не экзеипляр абб 88 < зз>п .Ссииигег >пвтзпсе зг Ох008бС308> Обратите внимание на изменение порядка следования операндов в вызове метода габб: аргумент ве1Г в действительности находится справа от оператора +, а аргумент отзе г — слева. Любой двухместный оператор имеет похожий правосторонний метод перегрузки (например, о01 и гап1 ). Обычно правосторонний метод, такой как габб просто изменяет порядок следования операндов и повторно выполняет операцию сложения, чтобы вызвать метод абб, в котором находится основная реализация операции.
Кроме того, следует заметить, что здесь х и у — это экземпляры одного и того же класса — когда в выражении участвуют экземпляры разных классов, интерпретатор предпочитает вызывать метод экземпляра, расположенного слева. Правосторонние методы — это достаточно сложная тема, и на практике они используются очень редко — к ним требуется обращаться только в том случае, когда необходимо обеспечить для оператора возможность перестановки операндов, и если вообще необходима реализация поддержки этого оператора. Например, эти методы могут использоваться в классе уэсте г, но в таких классах, как Евр1оуее или Впттоп, скорее всего, они не нужны.
саИ обрабатывает вызовы Метод са11 вызывается при вызове вашего экземпляра. Это не повторяющееся определение — если метод са11 присутствует, интерпретатор будет вызывать его, когда экземпляр вызывается как функция. Это позволяет экземплярам классов имитировать поведение функций: »> с1ввв Ргсб: бзт 1п11 (ве1Г, чз1се): зз1Г. чз1из чз1чз бзт сз11 (зе1Г, с(лег). гезчгп зе)т.чз1зе * ствег »> х = Ргсб(2) »> х(3) б »> х(4) 8 В этом примере реализация метода са11 может показаться ненужной. То же самое поведение можно реализовать с помощью простого метода: 621 Перегрузка операторов »> о1ззв Ргоб.
Оз1 1п11 (вв11, чв1из): зв11.ча1ие = чв1из Оз1 оозр(зз11, отпзг): гзтигп вз11.чв1ие отпвг »> х = Ргос(3) »> х.оозр(3) 9 »> х.оозр(4) 12 Однако метод са11 может оказаться удобнее при взаимодействии с прикладными интерфейсами, где ожидается функция, — это позволяет создавать объекты, совместимые с ожидающими получить функцию интерфейсами, которые к тому же способны сохранять информацию о своем состоянии между вызовами. Фактически этот метод занимает третье место среди наиболее часто используемых методов перегрузки операторов — после конструктора тшт и методов форматирования втг и геог функциональные интерфейсы и программный код обратного вызова Инструментальный набор для создания графического интерфейса ТЫпвег, с которым мы познакомимся далее в этой книге, позволяет регистрировать функции как обработчики событий (они же — функции обратного вызова); когда возникают какие-либо события, Т)т(п(ег вызывает зарегистрированные объекты.
Если вам необходимо реализовать обработчик событий, способный сохранять свое состояние между вызовами, вы можете зарегистрировать либо связанный метод класса, либо экземпляр класса, который с помощью метода са11 обеспечивает совместимость с функциональным интерфейсом. В программном коде этого раздела оба варианта — х. совр из второго примера и экземпляр х из первого — могут передаваться в виде объектов функций. В следующей главе я более подробно расскажу о связанных методах, а пока разберем гипотетический пример использования метода са11 для построения графического интерфейса. Следующий класс определяет объект, поддерживающий функциональный интерфейс, и, кроме того, имеет информацию о состоянии, сохраняя цвет, в который должна окрашиваться нажатая кнопка: о)азз СаЫЬасх, оз1 тпзт (ве11, со1ог): в Функция и информация о состоянии зе!1.со1ог = со1ог Ое1 сап (ве11); В Поддерживает вазова бва аргументов рг(пт 'тигп', зв)г,со1ог Теперь мы можем зарегистрировать экземпляры этого класса в контексте графического интерфейса как обработчики событий для кнопок, Глава 24.
Подробнее о программировании классов 622 несмотря на то что реализация графического интерфейса предполагает вызывать обработчики событий как обычные функции без аргументов: сс1 = Са11саск('Ыце') № 'Залоинить' голубой цвет сЬ2 = Са11ЬасК('Вгееп') № Зарегистрировать обработчик № Зарегистрировать обработчик В1 = ВЫ(оп(соааапб=сш) В2 = Вцпоп(соааапс=сЬ2) Когда позднее кнопка будет нажата, объект экземпляра будет вызван как простая функция, точно как в следующих ниже вызовах. А по- скольку он сохраняет информацию о состоянии в атрибутах экземпля- ра, он помнит, что необходимо сделать: сш() № По событию выведет 'Ыце' сЬ2() № Выведет дгееп' сьз = (1ааьса со1ог='гес'.
тцгп г со1ог) № или: по уиолчвнию рыпт сЬЗ() Во втором используются связанные методы класса и некий объект, ко- торый запоминает экземпляр ве1Г и ссылку на функцию, так что потом можно вызывать простую функцию без использования экземпляра: с1авв Са11сасК; Оет тп11 (ве1(, со!от): ве1( со1ог = со1ог бет слапбеСЬ1ог(ве1№); рг(пт 'тцгп', ве1(.со1ог № Класс с информацией о состоянии № Обычный ииенованный метод сЫ = Са11ЬасК('Ыце') сЬ2 = Са11ЬасК( 'уе11оы') В1 = Вцс1оп(соааапб=сЫ .ссапсеСо1ог) № Ссылка, не вызов В2 = Во(гоп(соааапб=сь2 спапуесо1ог) № запоминаются функция+ее!г Когда позднее кнопка будет нажата, имитируется поведение графиче- ского интерфейса и вызывается метод спапдеСо1о г, который обработает информацию о состоянии объекта: ос)ест = Са11Ьвск( Ы це') сЬ = ос)ест.спапсеСо1ог сс() № Регистрация обработчика собитий № По событию вывелет Ыцв' Фактически это один из лучших способов сохранения информации о состоянии в языке РуЫтоп — он намного лучше способов, обсуждавшихся ранее и применявшихся к функциям (глобальные переменные, ссылки в область видимости объемлющей функции и изменяемые аргументы со значениями по умолчанию).
Благодаря ООП состояние можно сохранять явно, посредством присваивания значений атрибутам. Прежде чем двинуться дальше, рассмотрим еще два способа, которые используются программистами для сохранения информации о состоянии в функциях обратного вызова. В первом варианте используется 1аасба-функция с аргументами, имеющими значения по умолчанию: 623 Перегрузка операторов Этот прием является более простым, но менее универсальным, чем перегрузка операции вызова с помощью метода са11 . Еще раз напомню, что подробнее о связанных методах будет рассказываться в следующей главе. Кроме того, в главе 26 будет представлен еще один пример использования метода са11, который будет использоваться для реализации так называемого декоратора функции — вызываемого объекта, добавляющего уровень логики поверх внедренной функции.
Поскольку метод са11 позволяет присоединять информацию о состоянии к вызываемым объектам, этот прием является естественным для реализации функций, которые должны запоминать и вызывать другие функции. де! — это деструктор Конструктор тптт вызывается во время создания экземпляра. Противоположный ему метод Ое1 вызывается автоматически, когда освобождается память, занятая объектом (тоесть во время «сборки мусора«): »> с1883 11(о: оег 1п11 (зо1г, паве='опкпопп'): рг1пт 'Не11о', паве во1(.паве паве Оет Се1 (ве1Г): рг1пт 'ВооОЬуе', ве1т.паве »> Ьпап = 11(о('Вг1ап') Не!1о Вг1ап »> Ьг1ап = '1огеттв' ВооОЬуе Вгтап Здесь, когда переменной Ьг(зп присваивается строка, теряется последняя ссылка на экземпляр класса 11ге, что приводит к вызову деструктора.
Этот метод удобно использовать для реализации некоторых завершающих действий (таких как завершение соединения с сервером). Однако в языке Ру1)топ по целому ряду причин деструкторы используются не так часто, как в других объектно-ориентированных языках программирования. С одной стороны, интерпретатор автоматически освобождает память, занятую экземпляром, поэтому нет нужды выполнять очистку памяти в деструкторах.' С другой стороны, не всегда бывает возможным предсказать, когда произойдет уничтожение экземпляра, поэтому часто луч- В текущей реализации Ру(йоп на языке С кроме всего прочего нет необходимости закрывать файлы в деструкторах, потому что они автоматически закрываются при уничтожении объектов файлов. Однако, как упоминалось в главе 9, лучше все-таки явно закрывать файлы, потому что «автоматическое закрытие при уничтожении объектૠ— это особенность реализации, а ие самого языка (в ау()топ это поведение может отличаться).
624 Глава 24. Подробнее о программировании классов ше выполнять завершающие действия в явно вызываемом методе (или в инструкции с гуП1па!1у, которая описывается в следующей части книги) — в некоторых случаях в системных таблицах могут сохраняться ссылки на ваши объекты, что будет препятствовать вызову деструктора. Я привел достаточно много примеров использования перегрузки операторов.
Большая часть других методов перегрузки работают похожим образом, и все они — всего лишь ловушки для перехвата встроенных операций. Некоторые методы перегрузки, например, имеют уникальные списки аргументов или возвращаемые значения. Далее в книге вы увидите еще несколько примеров, но полный охват этой темы я оставляю за другими источниками информации. Пространства имен: окончание истории Теперь, когда мы уже исследовали объекты классов и экземпляров, повествование о пространствах имен в языке Ру1поп можно считать завершенным. Для справки я напомню здесь все правила, используемые при разрешении имен. Первое, что вам нужно запомнить: составные и простые имена интерпретируются по-разному, и некоторые области видимости служат для инициализации пространств имен объектов: ° Простые имена (например, Х) располагаются в областях видимости.
° Составные имена атрибутов (например, оо) ест. Х) принадлежат объектам пространств имен. ° Некоторые области видимости инициализируют пространства имен объектов (в модулях и классах). Простые имена: глобальные, пока не выполняется присваивание Поиск неполных простых имен выполняется в соответствии с правилом лексической видимости 1 ЕСВ, выведенном для функций в главе 16: Присваивакие (Х = иа1ое) Операция присваивания делает имена локальными: создает или изменяет имя Х в текущей локальной области видимости, если имя не объявлено глобальным. Ссылка (Х) Пытается отыскать имя Х в текущей локальной области видимости, затем в области видимости каждой из вмещающих функций, затем в текущей глобальной области видимости и, наконец, во встроенной области видимости.