0% found this document useful (0 votes)
72 views32 pages

Functional Programming in Python

This document provides an overview of functional programming concepts in Python. It defines functional programming as using functions as fundamental building blocks rather than objects or procedures. It then discusses key functional programming concepts like immutable data, first class functions, tail call optimization, mapping/reducing, recursion, currying, and higher order functions. It provides examples of functional code in Python using these concepts and compares it to non-functional code. Finally, it covers additional Python features that support functional programming like list comprehensions, anonymous functions, closures, and nested functions.

Uploaded by

rajiv_saha
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
0% found this document useful (0 votes)
72 views32 pages

Functional Programming in Python

This document provides an overview of functional programming concepts in Python. It defines functional programming as using functions as fundamental building blocks rather than objects or procedures. It then discusses key functional programming concepts like immutable data, first class functions, tail call optimization, mapping/reducing, recursion, currying, and higher order functions. It provides examples of functional code in Python using these concepts and compares it to non-functional code. Finally, it covers additional Python features that support functional programming like list comprehensions, anonymous functions, closures, and nested functions.

Uploaded by

rajiv_saha
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1/ 32

Functional Programming with

Python
Functionalprogrammingisaparadigmwhere
functions,notobjectsorprocedures,areusedasthe
fundamentalbuildingblocksofaprogram.
Whiletalkingaboutfunctionalcharacteristics,we
comeacrosshostofterms,somefamiliarandfewnot
sofamiliar.Letsdigdeeperintothemanddissect
eachoneofthem.Thethingsthatwehearare
immutabledata,firstclassfunctionsandtailcall
optimisation.Thesearelanguagefeaturesthataid
functionalprogramming.Next,wehearabout
mapping,reducing,pipelining,recursing,
currying4andtheuseofhigherorderfunctions.These
areprogrammingtechniquesusedtowritefunctional
code.Thelistgoesonparallelization,lazy
evaluation6anddeterminism.Theseareadvantageous
propertiesoffunctionalprograms.
An immutable piece of data is one that cannot be
changed. Some languages, like Clojure, make all
values immutable by default. Any mutating
operationscopythevalue,changeitandpassback

the changed copy. This eliminates bugs that arise


from a programmers incomplete model of the
possiblestatestheirprogrammayenter.
Languages that support first class functions allow
functions to be treated like any other value. This
means they can be created, passed to functions,
returned from functions and stored inside data
structures.

Tail call optimization is a programming language


feature.Eachtimeafunctionrecurses,anewstack
frameiscreated.Astackframeisusedtostorethe
argumentsandlocalvaluesforthecurrentfunction
invocation.Ifafunctionrecursesalargenumberof
times,itispossiblefortheinterpreterorcompilerto
run out of memory. Languages with tail call
optimisation reuse the same stack frame for their
entire sequence of recursive calls. Languages like
Python that do not have tail call optimization
generallylimitthenumberoftimesafunctionmay
recursetosomenumberinthethousands.

Currying means decomposing a function that takes


multipleargumentsintoafunctionthattakesthefirst
argumentandreturnsafunctionthattakesthenext
argument,andsoforthforallthearguments.
Functionsarefirstclass(objects).Thatis,everything
youcandowith"data"canbedonewithfunctions
themselves(suchaspassingafunctiontoanother
function).
However,Functionalcodecanbecharacterizedjust
byonething:theabsenceofsideeffects.Itdoesnt
relyondataoutsidethecurrentfunction,andit
doesntchangedatathatexistsoutsidethecurrent
function.Everyotherfunctionalthingcanbe
derivedfromthisproperty.
FollowingisapieceofcodewritteninPython,which
isunfunctional:
a=0
defincrement1():
globala[forcestheinterpretertousetheglobal
variable,a]

a+=1

Thisisanexampleoffunctionalfunction:
defincrement2(a):
returna+1

Functions as Objects
FunctionsarefirstclassobjectsinPython,
meaningtheyhaveattributesandcanbereferenced
andassignedtovariables.

defi_am_an_object(myarg):...
'''Iamanicefunction....
Pleasebemyfriend.'''...

returnmyarg...

print(i_am_an_object(1))
1
an_object_by_any_other_name=
i_am_an_object
print(an_object_by_any_other_name(2))
2
print(i_am_an_object)
<functioni_am_an_objectat0x100432aa0>
print(an_object_by_any_other_name)
<functioni_am_an_objectat0x100432aa0>
print(i_am_an_object.__doc__)
'Iamanicefunction.\nPleasebemyfriend.'

Higher-Order Functions
Pythonsupportshigherorderfunctions,meaning
thatfunctionscanacceptotherfunctionsas
argumentsandreturnfunctionstothecaller.
Map,reduceandfilter,thefunctions,whichhelp
ustoworkwithdatastructuresrelyonhigherorder
functionsfortheiroperations.Allthethreefunctions
acceptafunctionreferenceasanargumenttoact
uponeachoftheelementsofthelistpassedasthe
secondargument.
resultant_list=map(func,seq)
Here,funcisafunctionwhosereference/pointer
ispassedontothefunctionmap.
Belowisanexampleofhigherorderfunction
deftransformer(element):
returnelement*5
defmy_map(funct,element_list)

modified_list=[]
forelementinelement_list:
modified_list.append(funct(element))
returnmodified_list
seq=[1,2,3,4,5]
transformed_list=my_map(transformer,seq)
print(transformed_list)
[5,10,15,20,25]

Anonymous Functions
AnonymousfunctionsinPythonarecreatedby
usingthelambdastatement.Alambdaisaninline
function.Thisapproachismostcommonlyused
whenpassingasimplefunctionasanargumentto
anotherfunction.Ittakesanynumberofarguments
(includingoptionalarguments)andreturnsthevalue
ofasingleexpression.lambdafunctionscannot
containcommands,andtheycannotcontainmore
thanoneexpression.
Thesyntaxconsistsofthelambdakeywordfollowed
byalistofarguments,acolon,andtheexpressionto
evaluateandreturn.Theparametersofthelambdaare

definedtotheleftofthecolon.Thefunctionbodyis
definedtotherightofthecolon.Theresultof
runningthefunctionbodyis(implicitly)returned.
deff(x):...
returnx*2...
print(f(3))
6
g=lambdax:x*2
g(3)
6
(lambdax:x*2)(3)
6
lambdafunctioncanbeusedwithoutevenassigning
ittoavariable.Thismaynotbethemostusefulthing
intheworld,butitjustgoestoshowthatalambdais
justaninlinefunction.
Anotherexample:
processFunc=collapseand(lambdas:"
".join(s.split()))or(lambdas:s)

alambdafunctionisalwaystrueinabooleancontext.
(Thatdoesn'tmeanthatalambdafunctioncan'treturn
afalsevalue.Thefunctionisalwaystrue;itsreturn
valuecouldbeanything.)
Intheaboveexample,processFuncisnowa
function,butwhichfunctionitisdependsonthe
valueofthecollapsevariable.Ifcollapseistrue,
processFunc(string)willcollapsewhitespace;
otherwise,processFunc(string)willreturnits
argumentunchanged.

Nested Functions
Functionscanbedefinedwithinthescopeofanother
function.Ifthistypeoffunctiondefinitionisused,
theinnerfunctionisonlyinscopeinsidetheouter
function,soitismostoftenusefulwhentheinner
functionisbeingreturned(movingittotheouter
scope)orwhenitisbeingpassedintoanother
function.
Inthegivenexample,anewinstanceofthe
functioninner()iscreatedoneachcalltoouter().That
isbecauseitisdefinedduringtheexecution
ofouter().Thecreationofthesecondinstancehasno
impactonthefirst.
defouter():...
definner(a):...
returna...
returninner...
f=outer()
print(f)

<functioninnerat0x1004340c8>
print(f(10))
10
f2=outer()
print(f2)
<functioninnerat0x1004341b8>
print(f2(11))
11

Closures
Essentially,aCLOSUREisafunctionobjectthat
remembersvaluesinenclosingscopesregardlessof
whetherthosescopesarestillpresentinmemory.
Anestedfunctionhasaccesstotheenvironmentin
whichitwasdefined.Thedefinitionoccursduring
theexecutionoftheouterfunction.Therefore,itis
possibletoreturnaninnerfunctionthatremembers
thestateoftheouterfunction,evenaftertheouter
functionhascompletedexecution.Thismodelis
referredtoasaclosure.

defouter2(a):...
definner2(b):...
returna+b...
returninner2...
add1=outer2(1)

print(add1)
<functioninner2at0x100519c80>
print(add1(4))
5
print(add1(5))
6
add2=outer2(2)
print(add2)
<functioninner2at0x100519cf8>
print(add2(4))
6
print(add2(5))
7

Closurescanbeusefulinthefollowing
scenarios:

Replacinghardcodedconstants
Eleminatingglobals
Providingconsistentfunctionsignatures
ImplementingObjectOrientation

List comprehensions
Listcomprehensionsareeasywaysofgenerating
listsfromagivenlist.Considerthefollowingcodeto
generatealistcontainingnumbersfrom1to25:

alist=[]
foriinrange(1,26):
...alist.append(i)
print(alist)
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
18,19,20,21,22,23,24,25]

Analternative,functionalapproachtothesame
wouldbeasfollows:

alist=[iforiinrange(1,26)]
print(alist)
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
18,19,20,21,22,23,24,25]

Noticethatthiscodeismoreintuitiveandeasy
tounderstandandbecomesshorteraswell!
However,whileimplementingalistcomprehension
makesuretotakecareofanyexceptionscenario,as
thecodeislikelytothrowexceptionsiftheexception
scenariosarenotaccountedfor.
Anotherexamplehowtostripwhitespace
fromalistofstrings:

alist=['Thisisline1\n','Thisisline2\n','',
'Thisisline3\n']
[line.strip()forlineinalist]
['Thisisline1','Thisisline2','','Thisisline3']

Heresamodificationoftheabove,whichtestsif
astringisanullstring,anddoesntprintifthatisthe
case.

[line.strip()forlineinalist
...ifline!='']
['Thisisline1','Thisisline2','Thisisline3']
Theactualsyntaxoflistcomprehensionisas
follows:
[expressionforiteminsequenceifcondition]
Thiscanalsoberememberedinthefollowingway:
Resultant_list=[transformiterationfilter]

TheequivalentPythoncodefortheaboveis
shownbelow:
foriteminsequence:
if(condition):
expression

LoopofLoops:

Itsworthmentioningthatyoucanuselist
comprehensionstoiterateonmorethanonelist.For
example:
list_a=['A','B']
list_b=[1,2]
[(x,y)forxinlist_aforyinlist_b]
[('A',1),('A',2),('B',1),('B',2)]
Here,thefirstlististheouterloopandthelastloopis
theinnerloop.Alsonotethatthismethodreturnsa
listoftuples.
Ifyoudlikenestedlists,youcanalsonestonelist
comprehensionwithinanother.
list_a=['A','B']
list_b=['C','D']
[[x+yforxinlist_a]foryinlist_b]
[['AC','BC'],['AD','BD']]
Here,thelatterlistisexecutedfirst,whichmeansthatitis
theouterloopandthenthefirstloopisexecuted,makingit
theinnerloop.

Dictionary comprehension
Dictionarycomprehensionsareaneasywaytogeneratea
dictionarybyprocessingagivendictionary.
My_dict = {a:5, b:10, c:15, d:20, e:25, f:30}
another_dict = {k:v*2 for k:v in my_dict}

print(another_dict = %s %( another_dict))
another_dict = {a:10, b:20, c:30, d:40, e:50,
f:60}

Set Comprehensions
Setcomprehensionsallowsetstobeconstructed
usingthesameprinciplesaslistcomprehensions,the
onlydifferenceisthatresultingsequenceisaset.
Saywehavealistofnames.Thelistcancontain
names,whichonlydifferinthecaseusedtorepresent
them,duplicatesandnamesconsistingofonlyone
character.Weareonlyinterestedinnameslonger
thenonecharacterandwishtorepresentallnamesin
thesameformat:Thefirstlettershouldbecapitalised,
allothercharactersshouldbelowercase.
Giventhelist:
names=['Bob','JOHN','alice','bob','ALICE','J',
'Bob']
Werequiretheset:
{'Bob','John','Alice'}
Notethenewsyntaxfordenotingaset.Membersare
enclosedincurlybraces.
Thefollowingsetcomprehensionaccomplishesthis:

{name[0].upper()+name[1:].lower()fornamein
namesiflen(name) > 1 }

Map
Map takes a function and a collection of items. It
makesanew,emptycollection,runsthefunctionon
eachitemintheoriginalcollectionandinsertseach
return value into the new collection. It returns the
newcollection.
Mapisthususedtocreateanewcollectionoutofa
collectionafterprocessingeachitemofthecollection
usingagivenfunction.
r=map(func,seq)

Thefirstargumentfuncisthenameofafunctionand
thesecondasequence(e.g.alist)seq.
map()appliesthefunctionfunctoalltheelementsof
thesequenceseq.Itreturnsanewlistwiththe
elementschangedbyfunc

Example :

deffahrenheit(T):
return((float(9)/5)*T+32)
defcelsius(T):
return(float(5)/9)*(T32)
temp=(36.5,37,37.5,39)
F=map(fahrenheit,temp)
C=map(celsius,F)

Thisisasimplemapthattakesalistofnamesand
returnsalistofthelengthsofthosenames:

name_lengths = map(len, ["Mary", "Isla",


"Sam"])
print name_lengths # => [4, 4, 3]
This is a map that squares every number in the passed
collection:

squares = map(lambda x: x * x, [0, 1, 2, 3,


4])
print squares # => [0, 1, 4, 9, 16]

Reduce
Reducetakesafunctionandacollectionofitems.It
returns a value that is created by combining the
items.Thus,Reduceisusedtoaggregate(orreduce)a
particularcollectionintoavaluebyprocessingeach
item of the given collection with a particular
function.
Thisisasimplereduce.Itreturnsthesumofallthe
itemsinthecollection.
sum = reduce(lambda a, x: a + x, [0, 1, 2,
3, 4])
print sum # => 10

xis the current item being iterated over.ais the


accumulator.Itisthevaluereturnedbytheexecution

of the lambda on the previous item.reduce()walks


throughtheitems.Foreachone,itrunsthelambda
on the currentaandxand returns the result as
theaofthenextiteration.
Whatisainthefirstiteration?Thereisnoprevious
iterationresultforittopassalong.reduce()usesthe
firstiteminthecollectionforainthefirstiteration
andstartsiteratingattheseconditem.Thatis,the
firstxistheseconditem.

Filter
Asthenamesuggests,filterextractseachelementin
thesequenceforwhichthefunctionreturnsTrue.
ThesignatureoftheFilterfunction:
modified_list=filter(func,list)
Ittakesafunction,funcasitsfirstargument.func
returnsaBooleanvalue,i.e.eitherTrueorFalse.This
functionwillbeappliedtoeveryelementofthe
listlist.

OnlyiffuncreturnsTruewilltheelementofthelist
beincludedintheresultantmodified_list.
fib=[0,1,1,2,3,5,8,13,21,34,55]
result=filter(lambdax:x%2,fib)
printresult
[1,1,3,5,13,21,55]
result=filter(lambdax:x%2==0,fib)
printresult
[0,2,8,34]

You might also like