4.6. Closures¶
4.6.1. Rationale¶
Function local variables are stored on the stack (function stack frame)
Inner functions have access to outer functions variables (access to outer function stack)
In order to that work, you can call inner function only when outer function is running
def f(x):
def g(y):
return x + y
return g
4.6.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
4.6.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
4.6.4. Assignments¶
"""
* Assignment: Function Closure Define
* Complexity: easy
* Lines of code: 4 lines
* Time: 5 min
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`
Tests:
>>> assert callable(check)
>>> assert callable(check(lambda x: x))
>>> result = check(lambda x: x).__call__()
>>> result is None
True
"""
"""
* Assignment: Function Closure Call
* Complexity: easy
* Lines of code: 9 lines
* Time: 5 min
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 "Tests" 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ą "Tests" (patrz poniżej)
Tests:
>>> 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
"""