Саммерфилд - Программирование на Python 3 (1077331), страница 103
Текст из файла (страница 103)
Например: все(ов.раж.де1в1ае(к) Гог к вп Г!!ев 1Г х,епбвн(СП(".ру")) При этом получается тот же результат, что и в трех предыдущих примерах, но программный код получился более компактным. В дополнение к функциям, реализующим действия операторов языка РуСЬоп, модуль оре гаго г также предоставляет функции орегагог.агггдеггег() и орегагог.~!езде(- ге г(), первую из которых мы коротко рассматривали выше в этой главе.
Обе они возвращают функции, которые затем могут вызываться для извлечения определенных атрибутов или элементов. Операция получения среза может использоваться для извлечения последовательности, составляющей часть списка, а операция получения среза с заданным шагом может использоваться для извлечения последовательности частей списка (например, каждого третьего элемента, с помощью инструкции 1[:;3]); точно так же функция орегагог.11еадеггег() может использоваться для извлечения последовательности произвольных частей, например, орегагог.11еаде11ег(4, 5, 6, 11, 18)(1).
Функция, возвращаемая функцией орега1ог.11еадеггег(), не обязательно должна вызываться непосредственно, как показано в этом примере, — ее можно сохранить и передавать в виде аргумента функции вар(), 1111ег() или гбпсгоо!а. гебцсе(), а также использовать в словарях, списках или генераторах множеств. Когда необходимо выполнить сортировку, можно определить ключевую функцию. Эта функция может быть любой функцией, например, 460 Глава 8. Усовершенствованные приемы программирования лямбда-функцией, встроенной функцией или методом (таким как а!г.
1онег()), а также функцией, возвращаемой функцией орегагог, аС- сгдессег(). Например, предположим, что список 1 хранит объекты с атрибутом рг! о гсс у, тогда отсортировать список в порядке приоритетов можно следующим способом: 1. зогс(кеу=орегасог. ассгдессег("ргсогссу")). В дополнение к модулям сипссоо1а и орегасог, упоминавшимся выше, для обеспечения поддержки функционального стиля программирования может использоваться модуль ссегсоо1э.
Например, хотя можно выполнить итерации по двум или более спискам, применив к ним операцию конкатенации, но также можно реализовать альтернативный вариант с помощью функции 1Сегсоо1з. сПасп(), как показано ниже: Гог ча!че сп 1Сеггоо1а.спа!п(пата !!а!с, Сага 1!а!2, СаСа 1!аСЗ). Сага! ч= ча1ие Функция 1сегсоо1а. спа1п() возвращает итератор, который сначала дает последовательность значений из первой последовательности, затем последовательность значений из второй последовательности и т.д., пока не будут использованы все значения из всех последовательностей.
В модуле 1сегсоо1а имеется множество других функций, а в описаниях к ним приводится множество маленьких, но полезных примеров, с которыми стоит ознакомиться. Частично подготовленные функции Частичная подготовка функций — это создание функции из существующей функции и некоторых аргументов, в результате чего получается новая функция, которая выполняет те же действия, что и оригинальная функция, но некоторые ее аргументы оказываются фиксированными и не могут передаваться вызывающим программным кодом. Ниже приводится очень простой пример: еппзегасе! = гппссоо1а. рагс!а1(епппегасе, асагс=!) Гог !1по, 11пе !п епизегате1(1!паа): ргосеаа 1спе(с, 11пе) В первой строке создается новая функция, епсзегасес(). Она служит оберткой вокруг существующей функции (епиаега(е()) с именованным аргументом (а!а гс=!), поэтому при обращении к функции епизегасе1() будет вызвана оригинальная функция с фиксированным аргументом и со всеми остальными аргументами, заданными во время вызова, в данном случае — с аргументом 1спеэ.
Здесь функция епазегате! () была использована для обеспечения нумерации строк, начиная с 1. Использование частично подготовленных функций может упростить программный код, особенно, когда приходится вызывать одну и ту же функцию с одними и теми же аргументами снова и снова. Например, вместо того чтобы при обработке текстовых файлов в кодировке 1)Тг -8 Пример: чаЫ.ру 461 в каждом вызове функции орел() указывать режим и кодировку, мож- но просто создать пару функций с фиксированными аргументами: геасег = гипстоо1в.рагт1а1(ореп, еосе="гт", епсоо1пд="итт8") пг1тег = гипстаа1в. рагтта!(ореп, еосе4 "ет", епсостпр="итгз" ) Теперь текстовые файлы можно открывать для чтения вызовом геай- ег( г)!епазе) и для записи — вызовом ыг1тег( г11епазе).
1оасВиттоп = тк1птег.Виттоп(тгаае, техт="1оао", соееапо=гипстоо1в.рагтта1(ооАсттоп, "1оас")) вачеВиттоп = тктптег.Виттоп(ггаае, техт="Вача", соееапо=типстоо1в.рагтта1(соАсттоп, "вача")) Б данном примере используется библиотека графического интерфейса тк1птег, которая поставляется как стандартная часть РуФйоп. Класс 1ктптег. Во(топ используется для создания кнопок — в этом примере создаются две такие кнопки, обе они находятся в пределах одного и того же фрейма и на каждой отображается текст, указывающий их назначение.
Бо время создания каждой кнопки в аргументе сопаапз указывается функция, которая должна вызываться библиотекой тК(птег при нажатии кнопки, в данном случае это функция ооАст1оп(). Здесь была использована частично подготовленная функция, чтобы гарантировать, что первым аргументом в вызове функции воАс1топ() будет строка, определяющая, какая кнопка была нажата, благодаря чему ооАс11оп() сможет определить, какое действие следует выполнять.
Пример: чаЫ.ру Б этом разделе мы объединим дескрипторы с декораторами классов, чтобы реализовать мощный механизм создания атрибутов с проверкой. До сих пор при необходимости обеспечить проверку корректности значения, записываемого в атрибут, мы опирались на свойства (то есть создавали методы чтения и записи). Недостаток такого подхода заключается в том, что программный код, реализующий проверку, необходимо добавлять в каждый класс для каждого атрибута, где такая проверка необходима. Было бы намного проще и удобнее, если бы имелась возможность добавлять в классы атрибуты со встроенной проверкой корректности.
Ниже приводятся несколько примеров синтаксиса, который было бы желательно иметь: Дескрипторы, стр. 432 а Декораторы кпассае, стр. 438 Одной из наиболее типичных областей применения частично подготовленных функций является программирование графического интерфейса (о котором рассказывается в главе 13), где часто бывает удобно вызывать одну определенную функцию при нажатии на любую из множества кнопок.
Например: 4б2 Глава 8. Усовершенствованные приемы программирования оча1со втг(пд("паве", вар!у а11онео4еа1ве) Оча1ьв втгтпд("ргосост(О", еар!у а11онес48а)ве, гадах=ге.соар11е(г"(А-7](3]'тс(4)")) Оча1!С втг1пд("сатедогу", еарту а11ооес48а1ве, ассертаЫе= Ггоаепвет(("СопвоааЫев", "Нагсыаге", "Зоттнаге", Гаес1а"])) Еча11О поаоег("рг1се", атптаоа=о, аах1аоа=те6) Оча1Ш поаоег("Ооапт1ту", атп(оса=1, пах!воз=1000) с1авв Зтосх1теа: оет тп11 (ве1г, паве, ргооост!о, сатедогу, ргтсе, сопят!ту]: ве1(.паве = паве ве1т.ргосос(10 = ргооост16 ве1г.сатедогу = сатедогу ве1(.рг1се = рысе ве1т.соапттту = Ооапттту о Все атрибуты класса 8!ос]т11еа требуют проверки. Напривырюженил, мер, атрибут ргосост10 может содержать только непусстр.
624 тую строку, которая начинается с трех алфавитных символов верхнего регистра и заканчивается четырьмя цифрами. Атрибут сатедогу может содержать только непустую строку, которая должна иметь одно из указанных значений. И атрибут цоап!1ту может быть только числом в диапазоне от 1 до 1000 включительно. Если попытаться записать недопустимое значение, будет возбуждено исключение. а Проверка реализуется посредством объединения декора- Декораторы классов, торов классов и дескрипторов.
Как отмечалось выше, дестр. 438 кораторы классов могут принимать только один аргумент — декорируемый класс. Поэтому здесь используется прием, продемонстрированный при первом обсуждении декораторов классов, в результате применения которого были созданы функции ча110 втг!пд() и ча110 поаЬег(), принимающие любые желаемые аргументы и возвращающие декоратор, который в свою очередь принимает класс и возвращает модифицированную версию класса. Рассмотрим функцию ча110 втппд(): Се( ча110 втг1пд(аттг паве, вар!у а11онес=тгое, гецех=воле, ассертаЫе=ноле): оет оесогатог(с1в).' паве = " " + аттг паве Оет деттег(ве1Г): гетогп детаттг(ве1Г, паве) сег веыег(ве11, ча1ое); аввегт твтпвтапсе(ча1ое, в!г), (аттг паве + " аов! Ье а втгтпд"] 11 пот вар!у а11онео апо по! ча1ое: гатве на1оееггог("(О] аау пот ье сорту".гогаат( Пример: най,ру вссг пвае)) !г ((ассер1вые св пос иопе впб нв1нв по1 сп аооерсвь)е] ог (гедех св по1 иопе впб пос гецех.аассп(чв1ое))): гв!вв чв1чееггог("(О) свппос ье вв1 со (1]".гогавс( в1сг пвае, чв1че]) ввсв1сг(ве!г, папе, ча1не) вв1вссг(о1в, в1сг пвае, 6епвг!соевсг!рсог(цвссег, вес1ег)) гегогп с1в гвсчгп бесогасог Функция начинается с того, что создает функцию-декоратор, которая принимает класс в виде единственного аргумента.
Декоратор добавляет в декорируемый класс два атрибута: частный атрибут данных и дескриптор. Например, когда функция ча)Ы зСг!пяО вызывается с именем атрибута «ргос)исСЫ», класс ВСосК1сеа получает атрибут ргобосссб, который будет хранить строку идентификатора продукта, и дескриптор ргобос1!б атрибута, который будет использоваться для доступа к значению.
Например, если создать экземпляр класса инструкцией 11еа = Ясоск1сеа("ТЧ", "тчА4312", "Е1ессгссз1", 500, 1), мы сможем получать значение идентификатора продукта как !Сев. ргобос1сб и изменять его инструкцией, например, ссеа, ргобосс!б = "ТЧВ2100". Функция чтения, создаваемая декоратором, просто использует глобальную функцию цеСа11г(), возвращающую значение частного атрибута данных. Функция записи реализует проверку и в конце, для записи нового (и корректного) значения в атрибут данных, использует функцию весзссг(). В действительности частный атрибут данных создается при первой попытке присвоить ему значение. После создания функций чтения и записи снова вызывается функция весзссг() — на этот раз, чтобы создать новый атрибут класса с заданным именем (например, ргобосС!б) и с дескриптором типа Оепег!сцевсг!рсог в виде значения.