Функционалното програмиране на Python е един от 4-те основни стила на програмиране.

Функционалното програмиране на Python трябва да се опитате да овладеете, за да се възползвате от предимствата, които предоставя.

Функционално програмиране в Python

Функционалното програмиране е една от парадигмите, поддържани от езика за програмиране Python.

Основните предпоставки за пълноценно функционално програмиране в Python са: функции от по-висок ред, усъвършенствани инструменти за обработка на списъци, рекурсия и възможност за организиране на мързеливи изчисления.

Елементите на функционалното програмиране в Python могат да бъдат полезни за всеки програмист, тъй като ви позволяват хармонично да комбинирате изразителната сила на този подход с други подходи.

Съдържание

  • 1 Възможности
  • 1.1 Дефиниране и използване на функция
  • 1.2 Списък с включвания
  • 1.3 Вградени функции от по-висок порядък
  • 1.3.1 map()
  • 1.3.2 филтър()
  • 1.3.3 намали()
  • 1.3.4 apply()
  • 1.4 Затваряния
  • 1.5 Итератори
  • 1.6 модул functools
  • 1.7 Мързелива оценка
  • 1.8 Функционери
  • 2 бележки
  • 3 връзки
  • 4 Литература

Възможности

Дефиниция и използване на функция

Функция в Python може да бъде дефинирана с операторdefили с ламбда израз. Следните твърдения са еквивалентни:

def func(x, y): връщане x ** 2 + y ** 2

func = ламбда x, y: x ** 2 + y ** 2

Дефиницията на функцията съдържа формални аргументи. Някои от тях може да имат стойности по подразбиране. Всички аргументи със стойности по подразбиране идват след аргументи без стойности по подразбиране.

При извикване на функциядадени са действителните аргументи. Например:

Позиционните аргументи са на първо място. Те се съпоставят с официалните имена на аргументи по ред. След това следват посочените аргументи. Те са съпоставени по име и могат да бъдат посочени в извикване на функция в произволен ред.

Разбира се, всички аргументи, за които не са посочени стойности по подразбиране в описанието на функцията, трябва да присъстват в извикването на функцията. Не се допускат дублирани имена на аргументи.

Функцията винаги връща само една стойност (илиНяма, ако стойността не е зададена в оператораreturnили този оператор не се среща при достигане на края на дефиницията на функцията). Това обаче е незначително ограничение, тъй като върнатата стойност може да бъде кортеж.

След като дефинирате функция с ламбда израз, можете веднага да я използвате:

>>> (ламбда x: x + 2)(5) 7

Ламбда изразите са полезни за дефиниране на не толкова сложни функции, които след това се предават на други функции.

Функциите в Python са първокласни обекти, т.е. те могат да се използват в програма заедно с обекти от други типове данни.

Списък включвания

Списъчното разбиране (списъчно разбиране) е най-изразителната от функциите на Python. Например, за да изчислите списъка с квадрати на положителни цели числа, по-малки от 10, можете да използвате израза:

Вградени функции от по-висок ред

Python има функции, които приемат други функции като един от аргументите си:map(),filter(),reduce(),apply().

Функциятаmap()ви позволява да обработвате една или повече последователности, като използвате дадена функция:

Подобен (само със същата дължина на списъците) резултат може да се постигне с помощта насписък изрази:

Функциятаfilter()ви позволява да филтрирате стойностите на последователност. В получения списък само онези стойности, за които стойността на функцията за елемента е вярна:

Същото и със списъчните изрази:

Можете да използвате функциятаreduce(), за да организирате верижни изчисления в списък. Например произведението на елементите на списък може да се изчисли по следния начин (Python 2):

Изчисленията се извършват в следния ред:

Веригата на повикванията е свързана с междинен резултат (res). Ако списъкът е празен, третият параметър просто се използва (в случай на произведение от нулеви фактори, това е 1):

Разбира се, междинният резултат не е непременно число. Може да бъде всеки друг тип данни, включително списък. Следващият пример показваобратната странана списък:

За най-често срещаните операции в Python има вградени функции:

Python 3 няма вградена функцияreduce(), но тя може да бъде намерена в модулаfunctools.

Функция за прилагане на друга функция към позиционни и именувани аргументи, дадени съответно от списък и речник (Python 2):

В Python 3 трябва да се използва специален синтаксис вместо функциятаapply():

Функциите, дефинирани вътре в други функции, са пълноценни затваряния (англ.closures):

Други инструменти за функционално програмиране са достъпни от стандартната библиотека (например модулаitertools) и други библиотеки.

Следващият пример илюстрира използването на итератори за изброяване и сортиране (итератор не може да бъде отпечатан с изразаprint, така че останалите стойности в него са поставени в списък):

Следващият пример илюстрира използването на модулаitertools:

Следващият пример илюстрира функциятаgroupby(group by), която генерира списък от двойки ключ-стойност и итератор, съответстващ на ключа (този итератор съдържа всички стойности на оригиналния списък със същата стойност на ключ). В примера ключът е True или False в зависимост от това дали стойността е положителна. (За целите на изхода всеки итератор се превръща в списък).

Има други итераторни функции в модулаitertools, които ви позволяват да изразите сбито (във функционален стил) и изчислително - ефективно - необходимите процеси за обработка на списъци.

модул functools

Python 2.5 представи модулаfunctoolsи по-специално възможността зачастично прилагане на функции:

(Прилагането на частична функция може също да се реализира с помощта на затваряния или функтори)

Мързелива оценка

Мързеливата оценка може да бъде организирана в Python по няколко начина, като се използват различни механизми:

  • най-простите логически операции или и и не оценяват втория операнд, ако резултатът се определя от първия операнд
  • ламбда изрази
  • потребителски дефинирани класове с мързелива логика за оценка или функтори
  • Генератори и генераторни изрази
  • (Python 2.5) if-expression има "мързелива" семантика (само операндът, който е необходим, се оценява)

Пример, който илюстрира работата на if-израз. С помощта на оператораprintможете да проследите кои функции всъщност са били извикани:

Няколко примера от книгата с рецепти:

  • Мързелив сорт
  • Мързеливо обхождане на графика
  • Мързелива оценка на имота
  • къри

Функтори

Функционеринаименувайте обекти, които са синтактично подобни на функциите, тоест поддържат операцията за извикване. За да дефинирате функтор, трябва да претоварите оператора()с помощта на метода__call__.

В Python функторите са абсолютно същите като функциите, с изключение на специалните атрибути (func_codeи някои други). Например функторите могат да бъдат предадени като функции за обратно извикване към C код.

Функционерите ви позволяват да замените някои трикове, свързани с използването на затваряния, статични променливи и т.н.

По-долу е затварянето и неговият еквивалентен функтор:

Трябва да се отбележи, че кодът, използващ затваряне, ще работи по-бързо от кода, използващ функтор. Това се дължи на необходимостта от получаване на атрибутаvalна променливатаself(т.е. функторът изпълнява още една операция на Python).

Освен това функторите не могат да се използват за създаване на декоратори с параметри.

От друга страна, функторите имат достъп до всички OOP функции в Python, което ги прави много полезни за функционално програмиране.

Например, можете да напишете функтор, който ще "помни" операциите, извършени върху него, и след това ще ги повтаря. За да направите това, достатъчно е да претоварите специалните методи по подходящ начин.

Функционерите предоставят на Python способността за мързелива оценка, присъща на функционалните езици: вместо да оценяват резултата от израз, те динамично дефинират нови функции чрез комбиниране на съществуващи.

Функтор, дефиниран по този начин, въвежда значителни допълнителни разходи, тъй като преминава през извикванията на всички вложениламбдавсеки път, когато бъде извикан.

Възможно е да се оптимизира функторът чрез прилагане на техниката за генериране на байт код по време на изпълнение. Съответният пример и тестовете за скорост са в ПримериPython програми.

Когато използвате тази техника, скоростта на изпълнение няма да се различава от "статичния" код (с изключение на времето, необходимо за еднократно конструиране на получената функция).

Вместо байт код на Python можете да генерирате изход, например код на езика за програмиране C, други езици за програмиране или XML файлове.

Въпреки режийните разходи, мързеливата оценка може да осигури забележимо увеличение на скоростта в случаите, когато действията, обвити от мързелив функтор, са доста скъпи - например, те включват големи изчисления или достъп до диск.

Да предположим, че някакъв междинен резултатXе лениво оценен преди условния оператор; за него ще бъде създадена верига от функтори.

В този клон на условния оператор, където стойносттаXне се изисква по време на изчислението, тази верига от функтори просто ще бъде отхвърлена, без да води до скъпо изчисление.

В другия клон, къдетоXсе изисква за изчисляване на крайния резултат на функцията, функторната верига ще го оцени.

В същото време програмистът не трябва да следи кой от клоновете на алгоритъма може да не е необходима стойност: той може да очаква, че скъпото изчислениеXще се случи само когато резултатът от него не бъде отхвърлен.