[Tutor] Functional Programming in Python

Steven D'Aprano steve at pearwood.info
Fri Apr 3 05:07:02 CEST 2015


On Thu, Apr 02, 2015 at 11:52:40AM -0700, Danny Yoo wrote:
> >> What are your thoughts on Functional in Python?
> >> Currently I am re-writing functions to reduce their side effects.
> >> I am also removing the state from objects and putting it into a closure
> >> type function.
> >
> > That doesn't remove state, it just moves it to a different place.
> >
> > However, encapsulating state inside a closure, or an object, it often
> > the most effective and natural way to deal with a problem. Better than
> > passing around long and confusing numbers of variables!
> 
> Theoretically, I'd agree with this.  But engineering-wise, I'd
> recommend explicit structures or objects if possible when representing
> state.

Yes, I agree! Hence my comment about encapsulating state inside a 
closure *or an object* rather than keeping your application state in 
your head, passing around vast numbers of variables only because some 
other part of your application needs them...

[...]
> Let's make this concrete.  If we want to represent a coordinate, a
> pair of numbers, we could use raw closures for this...
> 
> ################################
> def pair(x, y):
>     def dispatch(msg):
>         if msg == 'x':
>              return x
>         if msg == 'y':
>              return y
>     return dispatch
> 
> p = pair(3, 4)
> print p('x')
> print p('y')
> ################################
> 
> And this works!
> 
> 
> But there's already a feature in the language that does this kind of
> aggregation.
> 
> ################################
> class pair(object):
>     def __init__(self, x, y):
>         self.x, self.y = x, y
> 
> p = pair(3, 4)
> print p.x
> print p.y
> #################################
> 
> This is something that folks expect and is well supported and understood.

Precisely. I was thinking more along the idea of using closures, or 
functools.partial, for encapsulating state in this way. Suppose we start 
with two global variables:

def greet():
    print "%s, %s!"  % (greeting, name)

greeting = "Salutations"
name = "Danny"

greet()


Yuck. The obvious fix is to turn the globals into parameters:

def greet(greeting, name):
    print "%s, %s!"  % (greeting, name)

and pass in the greeting and name you need. And for many purposes that 
is exactly the solution you need.

But... sometimes you don't want to have to manually keep track of this 
"greeting" variable just for the sake of passing it on to the greet() 
function. There are lots of solutions to that problem:

# Early binding default value.
def greet(name, greeting="Salutations"):
    print "%s, %s!"  % (greeting, name)

# Late binding default value.
GREETING = "Salutations"
def greet(name, greeting=None):
    if greeting is None:
        greeting = GREETING
    print "%s, %s!"  % (greeting, name)

# An object is overkill, but let's do it anyway
class Greeter:
    def __init__(self, greeting):
        self.greeting = greeting
    def greet(self, name):
        print "%s, %s!"  % (self.greeting, name)

mygreeter = Greeter("Salutations")
mygreeter.greet("Danny")


Or we can use a closure:

def make_greeter(greeting):
    def greet(name):
        print "%s, %s!"  % (greeting, name)
    return greet

greet = make_greeter("Salutations")
greet("Danny")



> This is not to say that closures are bad.  It's just to point out that
> just because functional programs use closures quite a lot, doesn't
> automatically mean closures are the most appropriate tool for
> everything.  If there are parts of the language that already do the
> sort of thing you're trying to accomplish, it might be good to reuse
> those parts, rather than reinvent the universe.

Agreed.

That's the beauty of Python: you can mix paradigms in the one piece of 
code. The downside of this is that it reduces the opportunities for many 
compile-time optimizations (e.g. the compiler cannot know for sure that 
any function is free of side-effects) but that's often an acceptable 
price to pay.

-- 
Steve


More information about the Tutor mailing list