How did I understand closures in python?

:)

I have used a function inside another function in python for many use cases. I was able to call and access the values very well.Some geeks pointed out there I am using closure. I was no clue where it is.

For example, This is one of my use-case, For various users I have to generate the proper email template based on the type of the template

def email_template(template_type):
if template_type == ‘signin’:
msg = “The sign in URL: ****"
elif template == ‘signup’:
msg = “The signup url is here: ****"
else:
msg = “Welcome!!”

def useraddress(name):
return “Hi <b>%s</b> !! \n\n %s, Thanks” % (name, msg)
    return useraddress

How I will use it?

in my ipython shell,

In [47]: template_obj = email_template(‘signin’)
In [48]: complete_body = template_obj(‘Navaneethan’)
In [49]: complete_body
Out[49]: ‘Hi <b>Navaneethan</b> !! \n\n The sign in URL: ****, Thanks’

Notice! Notice!

I am removing email_template from global namespace in my same ipython shell. Still that magic worked :)

In [50]: del email_template
In [51]: email_template
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
NameError Traceback (most recent call last)
<ipython-input-51–5a1109f97f3d> in <module>()
— → 1 email_template
NameError: name ‘email_template’ is not defined
In [52]: complete_body = template_obj(‘Python fanboy’)
In [52]: complete_body
Out[52]: ‘Hi <b>Python fanboy</b> !! \n\n The sign in URL: ****, Thanks’

Here is our Closure

We are using the function useraddress inside another function called email_template, and the variable msg is accessed by the inner function useraddress, that means the inner function can able to access the outside(surrounded) scope and variable.

To reiterate the previous sentence, the inner function can able to access the enclosed lexical scopes.

Even if you remove the email_template from global namespace, still the inner function will maintain the enclosed scope.

Oh! You don’t believe me?

In [85]: template_obj.func_closure
Out[85]: (<cell at 0x21db9f0: str object at 0x21f0fa8>,)
In [86]: template_obj.func_closure[0]
Out[86]: <cell at 0x21db9f0: str object at 0x21f0fa8>
In [87]: cl = template_obj.func_closure[0]
In [88]: cl.cell_contents
Out[88]: ‘The sign in URL: ****'

Let’s dive into lambda side

One more example,

In [54]: fun = []
In [55]: for i in range(5):
….: fun.append(lambda x: x + i)

I have created list of function objects using lambda which depends on the scope of outside person i

I am passing the value ‘2’ to be passed to each function in fun list as an argument, so that we would yield the result with the scope that it owns already.

What could be the result, if we iterate all the function from fun list, and passing a constant ‘2’ to the function object and calling it like

>>>fun[0](2) == ?
>>>fun[1](2) == ?
>>>fun[2](2) == ?

Guessed? Shouldn’t be 2, 3, 4?

But?

In [58]: for f in fun:
print f(2)
….:
6
6
6
6
6

The result is not the obvious.

Reason

Stackoverflow answers:

A closure will always remember the name and scope of the variable, not the object it’s pointing to. Since all the functions in your example are created in the same scope and use the same variable name, they always refer to the same variable.

So, if you want to point the object in the function instead of pointing ONLY Scope, we have to pass as keyword argument in each lambda expression

do it this way,

In [59]: fun = []
In [60]: for i in range(5):
fun.append(lambda x, i=i: x + i)
….:
In [61]: for f in fun:
print f(2)
….:
2
3
4
5
6

We are done here !!

Thanks for your time.

Show your support

Clapping shows how much you appreciated Navaneethan’s story.