| Што мы будзем вокладцы? |
|---|
|
У гэтай частцы мы разгледзім, як Python падтрымлівае яшчэ адзін стыль праграмавання: функцыянальнае праграмаванне (FP). Як з рэкурсіяй гэта сапраўды складаная тэма, якую вы можаце ігнараваць па цяперашні час. Функцыянальныя метады маюць некаторыя выкарыстоўвае ў паўсядзённай праграмавання і прыхільнікаў FP лічу, што гэта прынцыпова лепшы спосаб для распрацоўкі праграмнага забеспячэння.
Што такое функцыянальнае праграмаванне?
Функцыянальнае праграмаванне не варта блытаць з імператыўным (ці працэдурнага) праграмавання. Ні ён, як аб'ектна-арыентаванага праграмавання. Гэта штосьці іншае. Радыкальна не так, паколькі паняцці, якія мы будзем вывучаць знаёмыя паняцці пра праграмаванне, гэтак жа выказаў па-іншаму. Філасофія, як гэтыя паняцці ўжываюцца да рашэння праблемы таксама трохі адрозніваюцца.
Функцыянальнае праграмаванне гэта ўсё о выразах. Насамрэч іншы спосаб для апісання ФП можа быць, каб назваць гэта выраз арыентаванага праграмавання, бо ў FP усё зводзіцца да выраза. Вы павінны памятаць, што выраз набор аперацый і зменных, што прыводзіць да аднаго значэння. Так х == 5 з'яўляецца лагічны выраз. 5 + (7-У) арыфметычны выраз. І "Прывітанне свет". Загалоўныя () з'яўляецца радковы выраз. Апошняе таксама функцыю выкліку (ці стражэйша выкліку метаду) на аб'ект радка "Прывітанне свет" і, як мы ўбачым, функцыі вельмі важныя ў FP (Вы, магчыма, ужо здагадаліся, што з назвы!).
Функцыі выкарыстоўваюцца як аб'екты ў ПС. Менавіта яны часта праходзілі вакол рамках праграмы шмат у чым гэтак жа, як і іншыя зменныя. Мы бачылі прыклады гэтага ў нашых праграм з графічным інтэрфейсам, дзе мы прысвоілі імя функцыі ў камандзе атрыбут элемента кіравання Button. Мы лячылі функцыі апрацоўніка падзеі, як аб'ект і прысвойваецца спасылка на функцыю кнопкі. Гэта ідэя перадачы функцый вакол нашай праграмы мае ключавое значэнне для ПС.
Функцыянальныя праграмы таксама маюць тэндэнцыю быць моцна Спіс арыентаванай.
Нарэшце FP спрабуе засяродзіць увага на тое, што, а не як пра рашэнне праблемы. Гэта значыць, функцыянал праграмы павінны ўтрымоўваць апісанне праблемы, якую мае быць вырашыць, а не канцэнтраваць увагу на механізм рашэння. Ёсць некалькі моў праграмавання, якія накіраваны на працу такім чынам, адным з найболей шырока выкарыстоўваных з'яўляецца Haskell і вэб-сайт Haskell ( www.haskell.org ) мае мноства артыкулаў, якія апісваюць філасофіі FP, а таксама мовы Haskell. (Маё асабістае меркаванне такое, што гэта мэта, аднак яе бывае даволі завышана на абаронцаў ПС.)
Чыста функцыянальная праграма пабудавана на вызначэнні выраз, якое захоплівае мэта праграмы. Кожны чалец выраза, у сваю чаргу заява характарыстыка праблемы (магчыма, інкапсуляваныя як іншы выраз) і адзнакі кожнага з гэтых умоў у канчатковым выніку дае рашэнне.
Ну, гэта тэорыя. Гэта магчыма? Так, часам яна працуе вельмі добра. Для некаторых тыпаў праблема гэта натуральны і магутная тэхніка. Нажаль, для шматлікіх іншых праблем, ён патрабуе даволі абстрактнае мысленне стылі, пад моцным уплывам матэматычных прынцыпах. Атрыманы код часта далёка не чытаным для неадмыслоўца праграміста. Атрыманы код таксама вельмі часта нашмат карацей, чым аналагічны імператыўнага кода і больш надзейным.
Менавіта гэтыя якасці апошняга лаканічнасць і надзейнасць, якія прыцягнулі шматлікіх звычайных неабходна ці аб'ектна-арыентаваных праграмістаў для расследавання FP. Нават калі не прынялі ўсяго сэрца Ёсць некалькі магутных прылад, якія могуць быць скарыстаны ўсімі.
| FP і надзейнасць |
|---|
| Надзейнасць функцыянальных праграм часткова паступаюць вельмі цесныя адносіны паміж FP канструкцый і фармальных моў спецыфікацыі, такія як Z ці VDM. Калі праблемы, паказаныя ў фармальнай мове гэта даволі просты крок для перакладу спецыфікацыі ў мове FP, як Haskell. Вядома, калі ў спецыфікацыі на гэта не так, то выніковая праграма будзе проста сапраўды адлюстроўваюць памылкі!
Гэты прынцып вядомы ў вобласці кампутарнай навукі, як "смецце, смецце на выйсці". Уласцівай цяжкасць выраза патрабаванняў да сістэмы ў кароткай і недвухсэнсоўна застаецца адной з найсур'ёзных праблем распрацоўкі праграмнага забеспячэння. |
Як Python гэта зрабіць?
Python мае некалькі функцый, якія дазваляюць функцыянальны падыход да праграмавання. Гэтыя функцыі з'яўляюцца выгода ў тым, што яны могуць быць напісаны на Python досыць лёгка. Што з'яўляецца важнейшым, аднак гэта намер маецца на ўвазе ў іх становішча, а менавіта, каб праграміст Python для працы ў FP выявай, калі ён / яна жадае.
Мы будзем глядзець на некаторыя з функцый, якія прадстаўляюцца і паглядзець, як яны дзейнічаюць на некаторыя прыклады структур дадзеных, якія мы вызначаем як:
spam = ['pork','ham','spices']
numbers = [1,2,3,4,5]
def eggs(item):
return item
Карта (спыненне функцыі, парушэнне праводнасці)
Гэта функцыя ўжываецца функцыя Python, спыненне функцыі для кожнага чальца парушэнне праводнасці. Выраз:
L = map(eggs, spam) print L
Вынікі ў новы спіс (у дадзеным выпадку ідэнтычныя спам) вяртаецца ў L.
Мы маглі б зрабіць тое ж самае, напісаўшы:
for i in spam: L.append(i) print L
Звернеце ўвагу аднак, што карта функцыя дазваляе ўхіліць неабходнасць ва ўкладзены блок кода. З аднаго пункта гледжання, што змяншае складанасць праграмы на адзін узровень. Мы бачым, што, як паўтаральныя тэмы FP, што выкарыстанне функцый FP змяншае адносную складанасць кода, ухіляючы блокі.
фільтр (спыненне функцыі, парушэнне праводнасці)
Як вынікае з назвы фільтра экстракты кожнага элемента ў паслядоўнасці, для якіх функцыя вяртае True. Разгледзім наш спіс нумароў. Калі мы жадаем стварыць новы спіс толькі няцотныя лікі, мы можам вырабіць яго вось так:
def isOdd(n): return (n%2 != 0) # use mod operator
L = filter(isOdd, numbers)
print L
Акрамя мы можам напісаць:
def isOdd(n): return (n%2 != 0)
for i in numbers:
if isOdd(i):
L.append(i)
print L
Ізноў заўважым, што звычайны код патрабуе двух узроўняў водступаў для дасягнення таго ж выніку. Ізноў павялічыць водступ указанне павялічыць складанасць кода.
скарачэнне (спыненне функцыі, парушэнне праводнасці)
Паменшыць функцыя трохі меней відавочна, у яго намеры. Гэта функцыя змяншае спісу адно значэнне, камбінуючы элементы з дапамогай пастаўлянага функцыі. Напрыклад, мы маглі сума значэнняў спісу і вяртаць агульнае наступным чынам:
def add(i,j): return i+j print reduce(add, numbers)
Як і перш мы маглі б зрабіць гэта больш традыцыйна, як гэта:
res = 0
for i in range(len(numbers)): # use indexing
res = res + numbers[i]
print res
Хоць, што дае той жа вынік у дадзеным выпадку, гэта не заўсёды так проста. Што паменшыць насамрэч гэта выклік функцыі пастаўляецца праходзілая першых двух чальцоў паслядоўнасці і замяняе іх вынік. Іншымі словамі больш дакладнае ўяўленне пра скарачэнні, як гэты:
def reduce(numbers): L = numbers[:] # make a copy of original while len(L) >= 2: i,j = L[0],L[1] # use tuple assignment L = [i+j] + L[2:] return L[0]
Яшчэ раз мы бачым тэхніку FP зніжэнні складанасці кода, пазбягаючы неабходнасці водступам блок кода.
lambda
Адной з асаблівасцяў вы маглі заўважыць у прыкладах дагэтуль з'яўляецца тое, што функцыі перадаюцца FP функцыі, як правіла, вельмі кароткі, часта толькі аднаго радка кода. Каб захаваць высілкі вызначальных мноства вельмі маленькіх функцый Python падае іншай дапамогі FP - lambda. Назва адбываецца ад lambda частка матэматыкі, званы lambda-вылічэнні, які выкарыстоўвае грэцкая літара Лямбда прадставіць аналагічную канцэпцыю.
Lambda гэта тэрмін, выкарыстоўваны для пазначэння ананімную функцыю, гэта значыць блок кода, якія могуць быць выкананы як калі б гэта была функцыя, але без назвы. Лямбда можа быць вызначаны ў любым месцы праграмы, юрыдычным выразам Python можа адбыцца, гэта азначае, мы можам выкарыстоўваць іх у нашы функцыі ПС.
Lambda выглядае наступным чынам:
lambda <aParameterList> : <a Python expression using the parameters>
Такім чынам дадаць функцыю вышэй можа быць перапісаны так:
add = lambda i,j: i+jІ мы можам пазбегнуць вызначэнні лініі цалкам за кошт стварэння ў lambda-заклік да скарачэнню, напрыклад, так:
print reduce(lambda i,j:i+j, numbers)
Аналагічным чынам мы можам перапісаць нашу карту і фільтр прыклады наступным чынам:
L = map(lambda i: i, spam) print L L = filter(lambda i: (i%2 != 0), numbers) print L
Спіс Разуменне
Спіс разумення з'яўляецца тэхніка для будаўніцтва новых спісаў запазычаныя з Haskell і ўведзена ў Python пачынальна з версіі 2.0. Яна мае некалькі невыразных сінтаксіс, падобныя на матэматычныя пазначэнні гэтага набору. Гэта выглядае наступным чынам:
[<expression> for <value> in <collection> if <condition>]
Што эквівалентна:
L = []
for value in collection:
if condition:
L.append(expression)
Як і ў іншых FP будуе гэта эканоміць некалькі радкоў і двух узроўняў укладзенасці. Давайце зірнём на некаторыя практычныя прыклады.
Першым чынам, давайце ствараць спіс усіх цотных лікаў:
>>> [n for n in range(10) if n % 2 == 0 ] [0, 2, 4, 6, 8]
Гэта кажа, што мы жадаем спіс значэнняў (N), дзе N выбіраецца з дыяпазону 0-9 і п цотна (я% 2 == 0).
Стане ў канцы маглі, вядома, замяніць функцыі, пры ўмове, функцыя вяртае значэнне, Python можна інтэрпрэтаваць як лагічнае значэнне. Такім чынам шукае зноў у папярэднім прыкладзе мы маглі б запісаць яго ў выглядзе:
>>>def isEven(n): return ((n%2) == 0) >>> [ n for n in range(10) if isEven(n) ] [0, 2, 4, 6, 8]
Зараз давайце створым спіс квадратаў першых 5 нумароў:
>>> [n*n for n in range(5)] [0, 1, 4, 9, 16]
Звернеце ўвагу, што канчатковым, калі становішча не з'яўляецца неабходнай у кожным пэўным выпадку. Пры гэтым пачатковыя выраз N * N, і мы выкарыстоўваем усе значэнні з дыяпазону.
Нарэшце давайце выкарыстоўваць існую калекцыю, а дыяпазон функцый:
>>> values = [1, 13, 25, 7] >>> [x for x in values if x < 10] [1, 7]
Гэта можа быць скарыстана для замены фільтра наступныя функцыі:
>>> filter(lambda x: x < 10, values) [1, 7]
Спіскавыя не абмяжоўваюцца адной зменнай ці адзін тэст, аднак код пачынае станавіцца вельмі складаным, як больш зменных і выпрабаванні ўводзяцца.
Будзь comprehensions ці традыцыйных функцый, здаецца найболей натуральным і адпаведным да вас чыста суб'ектыўныя. Пры стварэнні новай калекцыі на аснове існай калекцыі можна выкарыстоўваць любой папярэдняй функцыі ПС ці новыя comprehensions спісу. Пры стварэнні цалкам новай калекцыі, як правіла, прасцей у выкарыстанні разумення.
Памятаеце, што ў той час як гэтыя канструкцыі могуць здацца прывабнымі, выразы, неабходныя для атрымання жаданага выніку можа стаць настолькі складаным, што прасцей за ўсё пашырыць іх на свае традыцыйныя эквіваленты Python. Існуе не сорамна ў гэтым - чытальнасць заўсёды лепш, чым невядомасць, асабліва калі невыразнасці дзеля быць разумным!
Іншыя канструкцыі
Вядома, у той час як гэтыя функцыі карысныя самі па сабе яны не з'яўляюцца дастатковымі для поўнага стылю FP у Python. Кіравальныя структуры мовы таксама павінны быць зменены, ці прынамсі заменены, на падыходзе FP. Адзін са спосабаў дасягнення гэтага з'яўляецца ўжыванне пабочны эфект, як Python ацэньвае лагічных выразаў.
Кароткае замыканне адзнакі
Паколькі Python выкарыстоўвае кароткія адзнакі ланцуга лагічных выразаў некаторыя ўласцівасці гэтых выразаў могуць быць скарыстаны. Нагадаем пра кароткае замыканне адзнакі: калі лагічны выраз вылічаецца адзнака пачынаецца з левага боку выраза і прыступае да правай, спыняючыся, калі яно не з'яўляецца неабходным для адзнакі далейшага вызначэння канчатковага выніку.
Прымаючы некаторыя пэўныя прыклады давайце паглядзім, як кароткае замыканне адзнакі працы:
>>> def TRUE(): ... print 'TRUE' ... return True ... >>>def FALSE(): ... print 'FALSE' ... return False ...
Спачатку мы вызначым дзве функцыі, якія кажуць нам, калі яны выконваюцца і вярнуць значэнне іх імёнаў. Зараз мы выкарыстоўваем гэтыя каб даследаваць, як лагічныя выразы вылічаюцца:
>>>print TRUE() and FALSE() TRUE FALSE False >>>print TRUE() and TRUE() TRUE TRUE True >>>print FALSE() and TRUE() FALSE False >>>print TRUE() or FALSE() TRUE True >>>print FALSE() or TRUE() FALSE TRUE True >>>print FALSE() or FALSE() FALSE FALSE False
Звернеце ўвагу, што толькі тады, калі першая частка слова і дакладна тады і толькі тады будзе другая частка будзе ацэньвацца. Калі першая частка няслушная, то другая частка не будзе ацэньвацца, бо выраз у цэлым не можа быць праўдай.
Гэтак жа ў ці на аснове выразы калі ў першай частцы дакладна, то другая частка не павінны быць ацэнены з цэлым павінна быць праўдай.
Існуе яшчэ адна асаблівасць пітонаў адзнацы лагічных выразаў, што мы можам скарыстацца, а менавіта, што пры адзнацы выраза Python не проста вярнуць true ці няма, а яна вяртае фактычнае значэнне выраза. Такім чынам, калі тэставанне на пусты радок (якая будзе лічыцца False) наступным чынам:
if "This string is not empty": print "Not Empty" else: print "No string there"
Python проста вяртае сам радок!
Мы можам выкарыстоўваць гэтыя ўласцівасці, каб прайграць галінаванні, як паводзіны. Напрыклад, выкажам здагадку, у нас ёсць кавалак кода, накшталт наступнага:
if TRUE(): print "It is True" else: print "It is False"
Мы можам змяніць гэты стыль FP пабудаваць:
V = (TRUE() and "It is True") or ("It is False")
print V
Паспрабуйце працаваць праз гэты прыклад, а затым замяніць выклік TRUE () з заклікам FALSE (). Такім чынам, выкарыстоўваючы кароткі адзнакі ланцуга лагічных выразаў мы знайшлі спосаб ухілення звычайных калі / іншае заяў ад нашых праграм. Вы можаце ўспомніць, што ў рэкурсіі тэму мы выявілі, што рэкурсія можа быць скарыстаны для замены цыклу. Такім чынам спалучэнні гэтых двух эфектаў можа выдаліць усе звычайныя структуры кіравання з нашай праграмы, замяніўшы іх з чыстага выраза. Гэта вялікі крок у кірунку забеспячэння чыстага стылю FP рашэнняў.
Каб пакласці ўсё гэта на практыку давайце пісаць цалкам функцыянальны стыль фактарыял праграмы з выкарыстаннем lambda замест Def, рэкурсіі замест завесы і кароткае адзнакі ланцуга замест калі / іншае:
>>> factorial = lambda n: ( (n <= 1) and 1) or ... (factorial(n-1) * n) >>> factorial(5) 120
І што насамрэч усё, што трэба зрабіць. Гэта можа быць не зусім так зразумелыя, як больш традыцыйныя код Python, але ён працуе і з'яўляецца чыста функцыянальны стыль функцыі ў тым, што гэты чысты выраз.
Высновы
У гэты момант вам можа быць цікава, што менавіта кропка ўсяго гэтага? Вы б не быць аднаму. Хоць FP прыцягвае шматлікіх кампутарных даследаванняў навукоўцаў (а часцяком і для матэматыкаў) большасць практыкуючых праграмістаў уяўляецца выкарыстоўваць FP метады рэдка і ў выглядзе гібрыднай моды змешваючы яго з больш традыцыйнымі імператыўны стылі, як яны лічаць мэтазгодным.
Калі ў вас ёсць ужываць аперацыі да элементаў у спісе, напрыклад, што карта, скарачэнні ці фільтр здаецца натуральным спосабам выказаць рашэнне, то абавязкова іх выкарыстоўваць. Проста часам вы можаце нават знайсці, што рэкурсія з'яўляецца больш мэтазгодным, чым звычайныя завесы. Яшчэ больш рэдка вы знойдзеце выкарыстоўваць для кароткіх адзнакі ланцуга, а не канвенцыі, калі / інакш - асабліва калі гэта патрабуецца ў выразе. Як і з любой прыладай праграмавання, не захапляйцеся з філасофіяй, а выкарыстоўваць любая прылада з'яўляецца найболей падыходным для задачы. Прынамсі, вы ведаеце, што існуюць альтэрнатывы!
Існуе адзін канчатковы пункт, каб зрабіць о lambda. Існуе адзін раён за межамі сферы FP, што lambda знаходзіць рэальнае ўжыванне, і гэта для вызначэння апрацоўнікаў падзей у праграмаванні графічнага інтэрфейсу. Апрацоўнікі падзей, часта вельмі кароткі функцый, ці, можа быць, яны проста выклікаць некаторыя буйныя функцыі некалькіх правадных значэнняў аргументу. У любым выпадку lambda-функцыі могуць выкарыстоўвацца ў якасці апрацоўніка падзей, які дазваляе пазбегнуць неабходнасць вызначыць мноства невялікіх асобных функцый і запоўніць прастору імёнаў з імёнамі, якія будуць выкарыстоўвацца толькі адзін раз. Памятаеце, што lambda-аператар вяртае функцыю аб'екта. Гэта функцыя аб'екта з'яўляецца адзін перадаецца віджет і завецца ў момант падзеі. Калі вы памятаеце, як мы вызначаем віджет кнопкі ў Tkinter, то lambda будзе выглядаць так:
def write(s): print s
b = Button(parent, text="Press Me",
command = lambda : write("I got pressed!"))
b.pack()
Вядома, у гэтым выпадку мы маглі б зрабіць тое ж самае, толькі прызначэнне параметру значэнне па змаўчанні для запісы () і прысваенні напісаць каманду значэнне кнопкі. Аднак нават тут, выкарыстоўваючы lambda-формы дае нам перавага, што адной запісы () можа зараз выкарыстоўвацца для некалькіх кнопак толькі шляхам перадачы іншага радка з lambda. Такім чынам, мы можам дадаць другую кнопку:
b2 = Button(parent, text="Or Me",
command = lambda : write("So did I!"))
b2.pack()
Мы таксама можам выкарыстоўваць lambda-пры выкарыстанні прывязкі тэхніку, якая пасылае аб'ект падзеі як аргумент:
b3 = Button(parent, text="Press me as well")
b3.bind(<Button-1>, lambda ev : write("Pressed"))
Ну, сапраўды, што для функцыянальнага праграмавання. Ёсць шмат іншых рэсурсаў, калі вы жадаеце паглядзець глыбей у яе, некаторыя з іх пералічаны ніжэй. Ні VBScript, ні JavaScript прамую падтрымку FP, але як могуць быць скарыстаны ў функцыянальным стылі вызначаецца праграмістам. Ключавыя асаблівасці ў тым, каб структура вашай праграмы як выразы і не даць пабочныя эфекты, змяняць зменныя праграмы.
Іншыя рэсурсы
- Існуе выдатны артыкул Дэвіда Мерца на вэб-сайце IBM о FP у Python. Ён пераходзіць у больш падрабязна пра кіравальныя структур і забяспечвае больш падрабязныя прыклады канцэпцыі.
- Іншыя мовы падтрымку FP нават лепш, чым Python. Прыклады ўключаюць: Lisp, Scheme, Haskell, ML і некаторыя іншыя. вэб-сайт Haskell у прыватнасці, складаецца з велізарная колькасць інфармацыі пра ПС.
- Існуе таксама група навін, comp.lang.functional, дзе вы можаце нагнаць выпушчанае на апошніх падзей і знайсці карысныя адказы.
- Ёсць некалькі спасылак кнізе можна знайсці на сайтах вышэй спасылцы. Адзін з класічных кніг, якія не зусім о FP але вечка прынцыпы таксама з'яўляецца Структура і інтэрпрэтацыя кампутарных праграм па Abelman, Суссман і Суссман. Гэты тэкст прысвечаны Схема пашыраная версія Lisp. Мой асабісты асноўнай крыніцай была кніга Haskell школа Выраз Падлогай Гудак які, натуральна, о Haskell.
Калі хтосьці лічыць, добрая спасылка, напішыце мне электроннай пошце з дапамогай прыведзенай ніжэй спасылцы.
| Што трэба памятаць |
|---|
|
Калі ў Вас ёсць пытанні ці каментары на гэтай старонцы, дашліце мне на пошту: alan.gauld @ btinternet.com
From users like you
“I am very impressed. The loan officers at Hanscom were great. They called me within minutes and took care of all the paperwork within the next twenty-four hours. Thanks to MoneyAisle, I am saving over $200 a month on my car payment.” -Oliver, Waltham, MA
“These were the fastest $2,000 we have ever made! With the help of MoneyAisle and their incredible service, we got both of our cars re-financed in no-time! Our truck went down from a 9.59% APR to a 2.99% APR ,and we saved $1,195. The other car went down because we got a nice 3.49% APR. On this loan we saved $885,which brings our total savings to: $2080! Thank you MoneyAisle!!!” -Gerlinde & Anton, Queen Creek, AZmore from people like you

