Саммерфилд - Программирование на Python 3 (1077331), страница 102
Текст из файла (страница 102)
Реализация метода начинаетея е копирования коллекции з1отз с созданием пустой коллекции, если коллекция э1отз отсутствовала. Попутно кортеж преобразуется в список, чтобы впоследствии имелась возможность изменять его. Из всех атрибутов, находящихся в словаре, мы выбираем те, что начинаются с префикса "оет " и являются вызываемыми, то есть те, которые представляют методы чтения. Для каждого метода чтения в список а1отэ добавляется частное имя атрибута, который будет хранить соответствующие данные, например, при наличии метода оет лазе() в список з1отз добавляется имя паве. После этого из словаря извлекается и удаляется ссылка на метод чтения по его оригинальному имени (обе эти операции выполняются за один раз, с помощью вызова метода Стет.
рор()). То же самое выполняется для метода записи, если таковой присутствует, и затем создается новый элемент словаря с соответствующим именем свойства в качестве ключа, например, для метода чтения с именем пег паза() свойство получит имя паае. Значением элемента будет свойство с методами чтения и записи (который может отсутствовать), которые были найдены и удалены из словаря. В конце оригинальный кортеж э1отз замещаетея модифицированным списком, в который были включены частные имена для каждого добавленного свойства, и вызывается метод базового класса, чтобы создать действительный класс, но уже с использованием модифицированного словаря.
Обратите внимание, что в данном случае мы должны явно передать метакласс методу базового класса — это необходимо делать всегда, когда вызывается метод пен (), потому что это метод класса, а не метод экземпляра. В этом примере нам не потребовалось переопределять метод тпы,(), потому что все необходимое было реализовано в методе пен (), однако вполне возможно переопределить оба метода: пен () и тптт () и в каждом из них выполнить свою часть работы.
Если использование механизма наследования и приема агрегирования сравнить с ручной дрелью, а использование декораторов н дескрипторов — с электрической дрелью, то использование метаклассов можно сравнить с лазерным лучом, дающим непревзойденную мощность и гибкость. Метаклассы не являются инструментом первой необходимости, исключая, разве что, разработчиков прикладных платформ, которым необходимо предоставить своим пользователям мощные средства, не заставляя их проходить многочисленные этапы, чтобы оценить предлагаемые преимущества. 457 Функциональное программирование Функциональное программирование Функциональный стиль программирования — это подход к программированию, когда вычисления программируются путем комбинирования функций, которые не изменяют свои аргументы, не обращаются к переменным, определяющим состояние программы, и не изменяют их, а результаты своей работы поставляют в виде возвращаемых значений.
Основное преимущество втого подхода к программированию состоит в том, что при его использовании (теоретически) намного проще разрабатывать функции по отдельности и проще отлаживать функциональные программы. Здесь также положительно сказывается тот факт, что функциональные программы не изменяют свое состояние, поэтому вполне возможно рассуждать об их функциях с математической точки зрения. С функциональным программированием тесно связаны три понятия: отображение, фильтрация и упрощение. Отображение предполагает совместное использование функции и итерируемого объекта и получение нового итерируемого объекта (или списка), каждый элемент которого представляет результат вызова функции для соответствующего элемента в оригинальном итерируемом объекте. Понятие отображения поддерживается встроенной функцией вар(), например: 1[от(авр(1ввьов х: х ° 2, [1, 2, 3, 4])) в вернет: [1, 4, 9, 1б] Функция вар() принимает в виде аргументов функцию и итерируемый объект и для большей эффективности возвращает итератор, а не список.
В данном примере мы принудительно преобразовали итерируемый объект в список, чтобы результат выглядел более понятно. в вернет: (1, 4, 9, 16] [к**2(огх(о[1, 2, 3, 4]] Часто вместо функции звр() можно использовать выражения-генераторы. Здесь был использован генератор списков, чтобы избежать необходимости применять функцию 1131(), а чтобы получить генератор списков, оказалось достаточно заменить внешние круглые скобки квадратными. Фильтрация предполагает совместное использование функции и итерируемого объекта и получение нового итерируемого объекта, в состав которого включаются все те элементы оригинального итерируемого объекта, для которых функция вернула значение Ттов. Это понятие поддерживается встроенной функцией т11(е г( ): 1твт(т>1твт(1ввовв х, х > О, [1, -2, 3, -4])) В вернет: [1, 3] Функция т11(ег() принимает в виде аргументов функцию и итерируе- мый объект и возвращает итератор.
В вЕрнЕт: [ 1, 3] [х бог х тл [ 1, -2, 3, -4] 1( х > 0] 458 Глава 8. Усовершенствованные приемы программирования Функцию с!!се г() всегда можно заменить выражением-генератором или генератором списков. Упрощение предполагает совместное использование функции и итерируемого объекта и получение в качестве результата отдельного значения, При этом используется следующий порядок работы: сначала функции передаются значения первого и второго элементов итерируемого значения, затем вычисленный результат и значение третьего элемента, затем вычисленный результат и значение четвертого элемента и т. д., пока не будут использованы все элементы. Это понятие поддерживается функцией (толстое!3. гезасе() из модуля гтепстоо!в.
Ниже приводятся две строки программного кода, выполняющие одни и те же вычисления: Гипстоо1в.гваисе(1аввва х, у: х у, (1, 2, 3, 4]) Гипстсо1в. гввссе(срвгатог. аи1, ( 1, 2, 3, 4]) В вернет; 24 В вернет. 24 гппссао1в.гасссе(орегассг.асс, (св.раса.двсвссв(х) гог х сп гс1вв)) Гипстоо1в.гввссв(орегаСог.ввв, аар(св.рата.детв(ге. Г11вв)) Использование функции аар( ) часто дает более компактный программный код, чем эквивалентный генератор списков или выражение-генератор, за исключением случаев„когда используется условное выражение. Здесь вместо выражения !васса х, у: х + у мы использовали функцию сложения орегассг, асс().
Если бы нам потребовалось определить суммарный размер только файлов с расширением .ру, можно было бы отфильтровать все файлы, не являющиеся файлами с программным кодом на языке РУС]соп. Ниже приводятся три варианта реализации этого действия: В модуле эре гасо г имеются функции, реализующие действия всех операторов языка РУС]соп, призванные упростить программирование в функциональном стиле. Здесь во второй строке была задействована функция орегасог.ас1(), чтобы избежать необходимости создавать лямбда-функцию, выполняющую умножение, как это сделано в первой строке.
В языке РуС]соп имеется еще несколько встроенных функций, выполняющих упрощение: а11(), принимающая итерируемый объект и возвращающая Тгсе, если для каждого элемента итерируемого объекта встроенная функция Ьсс1() возвращает значение Тгэе; апу(), возвращающая Тгве, если хотя бы для одного элемента итерируемого объекта будет получено значение Тгое; аах( ), возвращающая элемент итерируемого объекта с наибольшим значением; асп(), возвращающая элемент итерируемого объекта с наименьшим значением; ввв(), возвращающая сумму значений элементов итерируемого объекта.
Теперь, когда мы познакомились с ключевыми понятиями, рассмотрим несколько примеров. Начнем с двух способов получить суммарный размер всех файлов в списке тс1ев: Функциональное программирование гбпс1со1в. гебисе(орегагсг. абб, еар(ов. рагс. де1в1ае, Гыгег(1аеэба х: х.епбвн11П(".ру"), Г11ев))) гбпс1оо!в. гебисе(орега1ог. абб, еар(ов. ра1п. дегвваа, (к Гог х 1п Г(1ев вГ х.епбви11П(".ру")))) гипс1оо!в. гвбисе(орегагог. абб, (ов.
ра1п. дегв1ге(х) Гсг к (п Г1!ев 1Г к.епбвн11П( Вероятно, второй и третий вариант выглядят более предпочтительными, потому что они не требуют создавать лямбда-функцию, но выбор между использованием выражения-генератора (или генератора-списков) и функциями вар() и 1111ег() — зачастую лишь вопрос личных предпочтений. использование функций еар(), 1111ег() и гопсгоо1в. геббсе() часто позволяет устранить циклы, как было продемонстрировано в примерах выше. Эти функции особенно удобны, когда необходимо адаптировать программный код, написанный на функциональном языке программирования, при этом в языке Ру1йоп обычно имеется возможность заменить функцию аар() генератором списков, функцию г1!1ег() — генератором списков с условием и во многих случаях функцию галс(ос!в. геббСЕ() можяо ЗаМЕНИтъ таКИМи вСтрОЕннЫмИ функцияМИ, КаК а11(), апу(), вак(), в(п() и вба().