Python: Closures & Decorator

First Class functions are just like objects. You can pass them as an argument to other functions or you can return them from another function.

Closures take advantage of this feature. It remembers variables defined in the outer function even if it is returned.

def outer_function(name):
  greet = 'Hello, '
  def inner_function():
    print(greet + name)
  return inner_function

# outer_function is already returned
closure_func = outer_function('Sujeet')

# inner_function still has access to both variables: greet and name
closure_func() # Hello, Sujeet

What If we pass a function as an argument? Actually we can,

def greet_by_name(greet):
  def wrapper_func(name):
    print('Hello, ' + name)
    return greet()
  return wrapper_func


def greet():
  print('Greeting done') 

greet = greet_by_name(greet)
greet('Sujeet')

So, there is the decorator greet_by_name()!

Wait! What about @decorator?

It's there too, let's modify the above.

def greet_by_name(greet):
  def wrapper_func(name):
    print('Hello, ' + name)
    return greet()
  return wrapper_func

# decorator function takes whatever function is passed to it,
# and then assigns the return value

@greet_by_name
def greet():
  print('Greeting done') 

greet('Sujeet Agrahari')