Саммерфилд - Программирование на Python 3 (1077331), страница 71
Текст из файла (страница 71)
Мы не предусматриваем реализацию методов тпвегт(), гечегве() или вогт(), потому что ни один из них не соответствует понятию сортированного списка. Если попытаться вызвать какой-либо из них, будет возбуждено исключение Ат! г]сотеЕг гог. Если мы скопируем сортированный список, используя прием 1(: ], в результате будет получен объект типа 1!в!, а не типа Зогтее(1вт. Простейший способ получить копию сортированного списка состоит 321 Собственные классы коллекций в том, чтобы импортировать модуль сору и воспользоваться функцией сору. сору( ) — она достаточно интеллектуальна, чтобы скопировать сортированный список (и экземпляры большинства других классов) без какой-либо помощи. Однако мы решили реализовать явный метод сору(): пег сору(ве1г); ге!игл Яогтевшэт(ве!Г, эе1Г Кеу) Передавая в первом аргументе сам объект ве1(, мы гарантируем, что будет создана лишь поверхностная копия ве1(.
11вт вместо копирования и пересортировки. (Благодаря тому, что в методе 1п11 () присутствует предложение е1тг, выполняющее проверку типа.) Теоретически высокая скорость копирования таким способом недостижима для функции сору, сору(), однако мы легко можем исправить этот недостаток, добавив строку: соРу = соРу Когда вызывается функция сору, сору(), она сначала пытается использовать специальный метод сору () объекта и только в случае его отсутствия выполняет свой собственный программный код. Благодаря этой строке функция сору, сору() теперь сможет при работе с отсортированными списками использовать метод Вогтесс!вт. сору(). (То же самое возможно в случае реализации специального метода Еверсору (), но это немного сложнее — электронная документация модуля сору содержит все необходимые подробности.) Теперь мы завершили реализацию класса ЗогтеЕСтвт.
Б следующем подразделе мы будем использовать объект класса Зо гтес С! в! для хранения ключей класса Богсет)0!с!. Создание классов коллекций посредством наследования Класс Зогтео0!ст, который демонстрируется в этом подразделе, стремится максимально имитировать поведение класса д!ст. Основное отличие между ними состоит в том, что ключи класса 8огтесО!ст всегда упорядочены в соответствии с заданной ключевой функцией или в соответствии с функцией идентичности.
Класс ЗогтеООтст предоставляет тот же АР1, что и класс г)!ст (за исключением поддержки функции герт(), обеспечивающей возможность создания репрезентативной формы представления, пригодной для передачи функции вуа1( ) ), плюс два дополнительных метода, которые имеют смысл только для упорядоченной коллекции.' Класс Яо гтеертст, представленный здесь, отличаетсн от аналогичного класса иэ написанной этим жв автором книги ейарЫ 0Ш Ргоягаптлт1пя тч1!)т Ру1Ьол алс) Яс*, 1ЯВХ 0132354187, н от похожего класса в каталоге пакетов Рус)топ (Рус)гол Рас)тале 1лт)ех). Глава 6.
Объектно-ориентированное программирование Ниже приводятся несколько примеров, дающих представление о том, как работает Яо гтеб01ст: б = Яогтебртст. Яогтебртст(бтст(я=1, А=2, у=5), втг. 1онег) б["а") = 4 б["Т") = 5 бе1 б["у") б["и") = 3 б["А") = 17 втг(б) 4 вернет: "('А'. 17, 'и': 3, 'в'; 1, 'Т': 5, 'г': 4)" В реализации класса Яогтеб0[с! используются оба механизма — агрегирование и наследование. Сортированный список ключей агрегирован в виде переменной экземпляра, тогда как сам класс Яо гтеб01ст наследует встроенный класс б1ст.
Наше знакомство с классом мы начнем с рассмотрения инструкции с1аяя и метода инициализации, а затем поочередно рассмотрим все остальные методы. с1авв Яогтеб01ст(бтст): бег тптт (ве1(, бтсттопагу=мспе, кеу=мопе, "кнагрв); б1сттопагу = б1ст1спагу ог () вирег(). тптт (б!ст!опагу) !Г Кидгрв: впрег().арбате(кнагря) яе!г. кеув = Яогтеб[!вт.Ясмеб(1вт(вирег() кеув(), кеу) В инструкции с1аяв указан базовый класс б1ст.
Метод инициализации пытается имитировать функцию б1с!(), но при этом имеет второй дополнительный аргумент, в котором передается ключевая функция. Вызов яарег(). 1пт! () используетдля инициализацииобъектакласса Яогтеб0тст метод б1с!. !п11 () базового класса. Точно так же, если методу были переданы именованные аргументы, вызывается метод бтс!. боба!а() базового класса, чтобы добавить их в словарь. (Обратите внимание, что принимается только одно вхождение любого именованного аргумента, поэтому ни один из ключей среди именованных аргументов Кнагря не может быть «Й1с11опагу» или «)теу».) Копии всех ключей словаря сохраняются в сортированном списке— в переменной ве1(.
Кеуя. При инициализации сортированного списка ему передается список ключей словаря с помощью метода базового класса б ! с!. Кеув( ) — мы не можем использовать метод Яо г теб 01ст. Кеув ( ), потому что он опирается на использование переменной ве17. Кеув, которая появится только после того, как будет создан сортированный список Яо г1еб [! я! ключей. бег арбате(яе17, бтст1опагу=мале, **кнагря): тг с!с!!благу 1в Моле: разя е117 тюпвтапсе(бтст!благу, б1ст): впряг().арбате(б!с!!благу) е1ве: 323 Собственные классы коллекций гог кеу, ча1че тп стст!влагу.ттеав(): ячрег() вес(теа (Кеу, ча1че) тт Ккагдв; вчрег() чраате(кгчагдв) ве1г кеув = зсгтесствт.зпгтесК!вт(вчрегО .кеув(), ве1Г.
Кеуя.кеу) Этот метод используется для добавления в словарь элементов другого словаря, или именованных аргументов, или и того и другого. Элементы, существующие только в другом словаре, добавляются в данный словарь, а если элементы с одинаковыми ключами присутствуют в обоих словарях, значения элементов другого словаря заместят значения элементов данного словаря.
Мы несколько расширили поведение словаря, так как сохраняем исходную ключевую функцию словаря, даже если другой словарь является объектом класса Зсгтесд!ст. Добавление элементов выполняется в два этапа. Сначала выполняется добавление элементов словаря. Если другой словарь является объектом подкласса, наследующего класс г)!с! (что, безусловно, относится и к классу Зсгтес0!ст), добавление выполняется вызовом метода с!ст.
црСа1е() базового класса — здесь очень важно использовать метод базового класса, потому что в случае вызова Зогтев0!сс. срвате() он попадет в бесконечную рекурсию. Если словарь не является объектом подкласса, наследующего класс о(ст, то выполняются итерации по его элементам, и каждая пара ключ-значение добавляется отдельно. (Если словарь не является объектом подкласса, наследующего класс отсс, и не имеет метода !тезя(), совершенно справедливо будет возбуждено исключение Аттг!ЬцтеЕггог.) Если были переданы именованные аргументы, точно так же вызывается метод црг)асс() базового класса, чтобы добавить их в словарь.
В результате добавления элементов список яе1г. Кеув становится недействительным, поэтому мы замещаем его новым списком типа Зсгсевб(вт, образованным из ключей словаря (опять же используя метод базового класса„потому что метод Зогтев0тст. Кеуя() опирается на использование списка яе!1. Кеув, который находится в процессе обновления), используя оригинальную ключевую функцию сортированногосписка. Ес1авваетаса Сет Ггсэкауя(с1в, ттегав)е, ча1че=Капе, Кеукаспе); гетпгп с1в((К: ча1че Гаг К тп ттегас)е), Кеу) Интерфейс класса Ь!ст включает метод класса с(с!, г гсвкеув( ). Этот метод используется для создания нового словаря на основе итерируемого объекта.
Каждый элемент итерируемого объекта становится ключом, а значением каждого ключа становится бспе или значение аргумента ча1це. Так как это метод класса, первый его аргумент автоматически передается интерпретатором Ру!Ьоп и является классом. Объекту класса т)!ст 324 Глава 6. Обьектно-ориентированное программирование будет передан класс бтст, а объекту класса 8огтеб0[ст будет передан класс 8огтеб01ст. Возвращаемое значение — словарь заданного класса. Например: с1ззз му01ст(8огтвдртст.зогтвсртст): рвзз С = Мустст.тгоэхвуз("УЕХИ8", 3) зтг(С) В гвтогпз: "('Е': 3, '1': 3, 'М': 3, '8': 3. 'у': 3)" о. с1ззз .
паве в гвтогпз; 'муртст' То есть при вызове метода дочернего класса в переменной с18 будет установлен корректный класс, точно так же, как при вызове обычных методов в переменной зе1( будет передана ссылка на текущий объект. Функции-генераторы Функция-генератор, или мептод-генератор — это функция, или метод, содержащая выражение у[е10. В результате обращения к функции-генератору возвращается итератор. Значения из итератора извлекаются по одному, с помощью его метода пехт ().
При каждом вызове метода пехт () он возвращает результат вычисления выражения у1е10. (Если выражение отсутствует, возвращается значение Иоле.) Когда функция-генератор завершается или выполняет инструкцию гетр гп, возбуждается исключение 8тор1(егэт[оп. На практике очень редко приходится вызывать метод пехт () или обрабатывать исключение 8(ор1(егзт1оп, Обычно функция- генератор используется в качестве итерируемого объекта.
Ниже приводятся две практически эквивалентные функции. Функция слева возвращает список, а функция справа возвращает генератор. Результаты, воспроизводимые обеими функциями, можно обойти с помощью цикла бог, например Гог 1еттег 1п 1еыег гарце("щ", "у" ):. Однако когда требуется получить список символов с помощью функции слева, достаточно просто вызвать ее как 1е(- тег гапце("щ", "у"), а для функции справа необходимо выполнить преобразование: 1[зт(!еттег галсе("щ", "у") ). Функции-генераторы и методы-генераторы (а также выражения-генераторы) более полно рассматриваются в главе 8.