Closures and Decorators
Python Closures
Let us explain closure by an example:
# This is the outer enclosing function
def print_msg(msg):
def printer():
# This is the nested function
print(msg)
return printer # returns the nested function
# Now let's try calling this function.
another = print_msg("Hello")
another()
# Output: Hello
This technique by which some data in our case "Hello" gets attached to the code - another() is called closure in Python.
Three characteristics of a Python closure are:
- it is a nested function, in our example: printer()
- it has access to a free variable in outer scope, in our example: msg.
- it is returned from the enclosing function, in our example: print_msg()
``
# Python Decorators make an extensive use of closures
Python Decorators
A decorator takes in a function, adds some functionality and returns it.
# a decorator takes in a function, adds some functionality and returns it.
# takes in function to be decorated
def make_pretty(func):
def inner():
print("I got decorated") # getting decorated
func() # back to the given function
return inner
def ordinary():
print("I am ordinary")
# will print: I am ordinary
ordinary()
decorated = make_pretty(ordinary)
decorated()
""" will print:
I got decorated
I am ordinary
"""
# decorator function (make_pretty) has added
## some new functionality to the original function (ordinary)
# annoation way
@make_pretty # syntactic sugar
def ordinary():
print("I am ordinary")
iam_special = ordinary()
""" will print:
I got decorated
I am ordinary
"""
Decorating functions with parameters
# Decorating functions with parameters
def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide by zero")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
divide(10,2)
""" will print:
I am going to divide 10 and 2
5.0
"""
divide(10,0)
""" will print:
I am going to divide 10 and 0
Whoops! cannot divide by zero
"""