Python Closures
Closures
Counter local - not working
def counter():
count = 0
count += 1
return count
print(counter())
print(counter())
print(counter())
1
1
1
Counter with global
- global
count = 0
def counter():
global count
count += 1
return count
print(counter())
print(counter())
print(counter())
count = -42
print(counter())
1
2
3
-41
Create incrementors
In order to use in various map-expressions, we need a couple of functions that - for simplicity - need to increment a number:
def f3(x):
return x + 3
def f7(x):
return x + 7
def f23(x):
return x + 23
print(f3(2))
print(f7(3))
print(f3(4))
print(f7(10))
print(f23(19))
5
10
7
17
42
Create internal function
def create_func():
def internal():
print("Hello world")
internal()
func = create_func()
internal()
Hello world
Traceback (most recent call last):
File "create_internal_func.py", line 8, in <module>
internal()
NameError: name 'internal' is not defined
Create function by a function
def create_func():
def internal():
print("Hello world")
#internal()
return internal
func = create_func()
#internal()
func()
Hello world
Create function with parameters
def create_func(name):
def internal():
print(f"Hello {name}")
return internal
foo = create_func("Foo")
foo()
bar = create_func("Bar")
bar()
Hello Foo
Hello Bar
Counter closure
- nonlocal
def create_counter():
count = 0
def internal():
nonlocal count
count += 1
return count
return internal
counter = create_counter()
print(counter())
print(counter())
print(counter())
print()
other = create_counter()
print(counter())
print(other())
print(counter())
print(other())
print()
print(count)
1
2
3
4
1
5
2
Traceback (most recent call last):
File "counter.py", line 23, in <module>
print(count)
NameError: name 'count' is not defined
Make incrementor with def (closure)
- closure
def make_incrementor(n):
def inc(x):
return x + n
return inc
f3 = make_incrementor(3)
f7 = make_incrementor(7)
print(f3(2))
print(f7(3))
print(f3(4))
print(f7(10))
5
10
7
17
Make incrementor with lambda
def make_incrementor(n):
return lambda x: x + n
f3 = make_incrementor(3)
f7 = make_incrementor(7)
print(f3(2))
print(f7(3))
print(f3(4))
print(f7(10))
5
10
7
17
Exercise: closure bank
- Create a closure that returns a function that holds a number (like a bank account) that can be incremented or decremented as follows:
- Allow for an extra paramter called
prevthat defaults toFalse. IfTrueis passed then instead of returning the new balance, return the old balance.
bank = create_bank(20)
print(bank()) # 20
print(bank(7)) # 27
print(bank()) # 27
print(bank(-3)) # 24
print(bank()) # 24
print(bank(10, prev=True)) # 24
print(bank()) # 34
Exercise: counter with parameter
Change the counter example to accept a parameter and start counting from that number.
Solution: closure bank
def create_bank(n = 0):
balance = n
def bnk(change = 0, prev=False):
nonlocal balance
prev_balance = balance
balance += change
if prev:
return prev_balance
else:
return balance
return bnk
bank = create_bank(20)
print(bank()) # 20
print(bank(7)) # 27
print(bank()) # 27
print(bank(-3)) # 24
print(bank()) # 24
print(bank(10, prev=True)) # 24
print(bank()) # 34
20
27
27
24
24
24
34
Solution: counter with parameter
def create_counter(count=0):
def internal():
nonlocal count
count += 1
return count
return internal
counter = create_counter()
print(counter())
print(counter())
print(counter())
print()
other = create_counter(42)
print(counter())
print(other())
print(counter())
print(other())
1
2
3
4
43
5
44