Python for Network Engineers

First Class Functions in Python and Closures

by: George El., March 2019, Reading time: 2 minutes

In this post I will explain first class functions. According to wikipedia: “In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. This means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.”

We saw in the post about lambda expressions, the map function which takes as an argument another function or a lambda expression. These functions that accept as arguments other functions are also called higher order functions. As a reminder I include the code here:

l = [1,2,3,4]
def sq(x):
    return x**2
print(list(map(sq,l)))
[1, 4, 9, 16]

In the post about local and enclosing scopes we saw this example:

def func1():
    a = 2
    def func2():
        print(a)
    func2()
func1()

But it is also possible func1 instead of running func2 to return func2

def func1():
    a = 2
    def func2():
        print(a)
    return func2
f = func1()

Now when I execute the above code, func1 returns func2 and I can assign it to another variable called f. Now I can call f and print a

def func1():
    a = 2
    def func2():
        print(a)
    return func2
f = func1()
f()
2

The output is 2. Here something happens that may seem strange. I run func1. func1 returns func2 and has finished executing and normally variable “a” should go out of scope. But because it is referenced by func2, it doesn’t. Instead “a” is called a free variable and is kept in association with func2. This inner function together with the free variable is called a closure. So when we return func2, we can think that we don’t only return func2, but we return func2 with its free variable a. Each closure has its own instance of free variable as shown below.

def func1(a):
    def func2():
        print(a)
    return func2
f1 = func1('hello')
f2 = func1('hi')
f1()
f2()

the output is

Hello
Hi

Lets make func2 accept an argument also.

def func1(a):
    def func2(msg):
        print(a+' '+msg)
    return func2
f1 = func1('hello')
f2 = func1('hi')
f1("george")
f2("george")

the output is

hello george
hi george

if we print the following:

print(f1.__closure__)
print(f1.__code__.co_freevars)

we get

(<cell at 0x00E254F0: str object at 0x00E25020>,)
('a',)

this tells us that the closure of f1 is a cell that points to an str object, and the free variable is a. The cell is an intermediary object that python creates and points to the free variable.

comments powered by Disqus