Closures and Decorators Slides
Closures and Decorators Slides
Closures and Decorators Slides
def func():
x = 1
y = 2
return x + y
Local functions
PI = TAU / 2
!
def func(x):
def local_func(n):
a = 'hello, '
return a + n
!
y = 2
return x + y
module.py
LEGB Rule
PI = TAU / 2
!
def func(x):
def local_func(n):
a = 'hello, '
return a + n
!
y = 2
return x + y
module.py
LEGB Rule
PI = TAU / 2
!
def func(x):
def local_func(n):
a = 'hello, '
return a + n
!
y = 2
return x + y
module.py
LEGB Rule
PI = TAU / 2
!
def func(x):
def local_func(n):
a = 'hello, '
return a + n
!
y = 2
return x + y
module.py
Local functions
def outer():
def inner():
print('inner')
inner()
Returning functions
def outer():
def inner():
print('inner')
return inner
!
i = outer()
i()
First-class
Functions
functions can be treated like any other object
Closures
def outer():
x = 3
!
def inner(y):
return x + y
!
return inner
!
i = outer()
Closures
def outer():
x = 3
!
def inner(y):
return x + y
!
return inner
!
i = outer()
Closures
def outer():
x = 3
!
def inner(y):
return x + y
!
return inner
!
i = outer()
Closures
!
x = 3
?
def inner(y):
return x + y
!
!
i = outer()
Closures
maintain references to objects from earlier scopes
Function
factory
function that returns new, specialized functions
!
@my_decorator
def my_function():
. . .
Decorators
@my_decorator!
def my_function(x, y):!
return x + y
Decorators
@my_decorator!
def my_function(x, y):! FUNCTION
OBJECT
return x + y
Decorators
def my_decorator(f):!
y):! FUNCTION . . .!
OBJECT
return new_f
Decorators
def my_decorator(f):!
FUNCTION FUNCTION
. . .!
OBJECT OBJECT
return new_f
Decorators
@my_decorator!
FUNCTION
def my_function(x, y):!
OBJECT
return x + y
Decorators
def vegetable():
return 'blomkål'
!
def animal():
return 'bjørn'
!
def mineral():
return 'stål'
Decorators
def vegetable():
return ascii(‘blomkål’)
!
def animal():
return ascii(‘bjørn’)
!
def mineral():
return ascii(‘stål’)
Decorators
def vegetable():
return ascii(‘blomkål’)
!
def animal():
return ascii(‘bjørn’)
!
def mineral():
return ascii(‘stål’)
Not
very
le. main
alab tain
y sc able.
ver
Not
Decorators
class MyDec:!
def __init__(self, f):!
@MyDec!
! . . .!
def func():!
!
. . .
def __call__(self):!
! . . .
Classes as decorators
Classes are
callable…
class MyDec:!
def __init__(self, f):!
@MyDec!
! . . .!
def func():!
!
. . .
def __call__(self):!
! . . .
Classes as decorators
class MyDec:!
def __init__(self, f):!
@MyDec!
! . . .!
def func():!
!
. . .
def __call__(self):!
! . . .
Classes as decorators
Applying a class
decorator creates a
new instance…
class MyDec:!
def __init__(self, f):!
@MyDec!
! . . .!
def func():!
!
. . .
def __call__(self):!
! . . .
Classes as decorators
Applying a class
decorator creates a
new instance…
class MyDec:!
def __init__(self, f):!
@MyDec!
! . . .!
def func():!
!
. . .
def __call__(self):!
! . . .
Decorating with
an instance calls
the instance.
class AnotherDec:!
def __call__(self, f):! @AnotherDec()!
! def wrap():! def func():!
! . . .! . . .
! return wrap
Instances as decorators
Decorating
with an
instance calls
the instance.
class AnotherDec:!
def __call__(self, f):! @AnotherDec()!
! def wrap():! def func():!
! . . .! . . .
! return wrap
@decorator1
@decorator2
@decorator3
def some_function():
. . .
Multiple decorators
@decorator1
@decorator2
@decorator3
def some_function():
. . .
Multiple decorators
@decorator1
@decorator2
def some_function():
. . .
!
Multiple decorators
@decorator1
@decorator2
def some_function():
. . .
!
Multiple decorators
@decorator1
def some_function():
. . .
!
!
Multiple decorators
@decorator1
def some_function():
. . .
!
!
Multiple decorators
def some_function():
. . .
!
!
!
functools.wrap()
return local_function
>>> p = function(5, 7)
A function
>>> p
<function function.<locals>.local_function at 0x10299f320>
>>> p.__closure__
(<cell at 0x1029bc8d8: int object at 0x100233120>,
<cell at 0x1029bc980: int object at 0x100233160>)
Closures and Decorators
def log_to(stream):
@wraps(func)
def logging_wrapper(*args, **kwargs):
print(func.__name__ + " was called" , file=stream)
return func(*args, **kwargs)
return logging_wrapper
return logging_decorator
@second_decorator @log_to(sys.stderr)
@logging_decorator
def another_function(x):
def some_function(x):
"""A decorated function"""
"""A decorated function"""
return x + x
return x * x
>>> print(some_function.__name__)
some_function
>>> print(some_function.__doc__)
A decorated function