3.8. Closures

3.8.1. Rationale

def f(x):
    def g(y):
        return x + y
    return g

3.8.2. Nested Function

  • Function inside the function

  • Nested functions can access the variables of the enclosing scope

def run():
    def hello():
        print('hello')
    return hello


hello()
# Traceback (most recent call last):
#     ...
# NameError: name 'hello' is not defined

run()
# <function run.<locals>.hello at 0x104e13700>

run()()
# hello

result = run()
result()
# hello

3.8.3. What is closure?

  • technique by which the data is attached to some code even after end of those other original functions is called as closures

  • Closures can avoid use of global variables and provides some form of data hiding

  • When the interpreter detects the dependency of inner nested function on the outer function, it stores or makes sure that the variables in which inner function depends on are available even if the outer function goes away

  • Method of binding data to a function without actually passing them as parameters is called closure

  • It is a function object obj that remembers values in enclosing scopes even if they are not present in memory

  • Closures provide some sort of data hiding as they are used as callback functions

  • This helps us to reduce the use of global variables

  • Useful for replacing hard-coded constants

  • Closures prove to be efficient way when we have few functions in our code

firstname = 'Mark'
lastname = 'Watney'

def hello():
    print(firstname, lastname)


hello()
# Mark Watney
firstname = 'Mark'

def run():
    lastname = 'Watney'

    def hello():
        print(firstname, lastname)

    return hello


result = run()
result()
# Mark Watney
firstname = 'Mark'

def run():
    lastname = 'Watney'

    def hello():
        print(firstname, lastname)

    return hello


result = run()
del run
result()
# Mark Watney

3.8.4. Assignments

3.8.4.1. Function Closure Define

  • Assignment name: Function Closure Define

  • Last update: 2020-10-13

  • Complexity level: easy

  • Lines of code to write: 4 lines

  • Estimated time of completion: 5 min

  • Solution: solution/function_closure_define.py

English
  1. Define function check which takes func: Callable as an argument

  2. Define closure function wrapper inside check

  3. Function wrapper takes *args and **kwargs as arguments

  4. Function wrapper returns None

  5. Function check must return wrapper: Callable

Polish
  1. Zdefiniuj funkcję check, która przyjmuje func: Callable jako argument

  2. Zdefiniuj funkcję closure wrapper wewnątrz check

  3. Funkcja wrapper przyjmuje *args i **kwargs jako argumenty

  4. Funkcja wrapper zwraca None

  5. Funkcja check ma zwracać wrapper: Callable

Output
>>> assert callable(check)
>>> assert callable(check(lambda x: x))
>>> result = check(lambda x: x).__call__()
>>> result is None
True

3.8.4.2. Function Closure Call

  • Assignment name: Function Closure Call

  • Last update: 2020-10-13

  • Complexity level: easy

  • Lines of code to write: 9 lines

  • Estimated time of completion: 5 min

  • Solution: solution/function_closure_call.py

English
  1. Define function check with parameter func: Callable

  2. Define closure function wrapper inside check

  3. Function wrapper takes arbitrary number of positional and keyword arguments

  4. Function wrapper prints hello from wrapper on the screen

  5. Function check must return wrapper: Callable

  6. Define function hello() which prints hello from function

  7. Define result with result of calling check(hello)

  8. Delete check using del keyword

  9. Call result

  10. Compare result with "Output" section (see below)

Polish
  1. Zdefiniuj funkcję check z parametrem func: Callable

  2. Zdefiniuj funkcję closure wrapper wewnątrz check

  3. Funkcja wrapper przyjmuje dowolną ilość argumentów pozycyjnych i nazwanych

  4. Funkcja wrapper wypisuje hello from wrapper

  5. Funkcja check ma zwracać wrapper: Callable

  6. Zdefiniuj funkcję hello(), która wypisuje hello from function

  7. Zdefiniuj zmienną result, która jest wynikiem wywołania check(hello)

  8. Skasuj check za pomocą słowa kluczowego del

  9. Wywołaj result

  10. Porównaj wyniki z sekcją "Output" (patrz poniżej)

Output
>>> from inspect import isfunction
>>> assert isfunction(hello)
>>> assert isfunction(result)
>>> assert not hasattr(__name__, 'check')

>>> hello()
hello from function

>>> result()
hello from wrapper

>>> check()
Traceback (most recent call last):
    ...
NameError: name 'check' is not defined