Decorators (Livehacking Screenplay)¶
Closures Recap¶
def decorator(param):
def wrapper():
print('wrapper called, param =', param)
return param
return wrapper
eins = decorator(1)
zwei = decorator(2)
blah = decorator('blah')
print('eins', eins())
print('zwei', zwei())
print('blah', blah())
$ python code/10-closures-recap.py
wrapper called, param = 1
eins 1
wrapper called, param = 2
zwei 2
wrapper called, param = blah
blah blah
|
|
Simple Decorator: Function Without Args¶
def decorator(func):
def wrapper():
print('wrapper called, func =', func.__name__)
return func()
return wrapper
def f1():
print('f1 called')
return 1
def f2():
print('f2 called')
return 2
f1 = decorator(f1)
f2 = decorator(f2)
print('f1 returned', f1())
print('f2 returned', f2())
$ python code/20-decorator-no-args.py
wrapper called, func = f1
f1 called
f1 returned 1
wrapper called, func = f2
f2 called
f2 returned 2
|
|
Decorators are Syntactic Sugar¶
def decorator(func):
def wrapper():
print('wrapper called, func =', func.__name__)
return func()
return wrapper
@decorator
def f1():
print('f1 called')
return 1
@decorator
def f2():
print('f2 called')
return 2
print('f1 returned', f1())
print('f2 returned', f2())
$ python code/30-decorator-syntactic-sugar.py
wrapper called, func = f1
f1 called
f1 returned 1
wrapper called, func = f2
f2 called
f2 returned 2
|
|
*args
, **kwargs
: A Debug-Decorator¶
def debug(func):
def wrapper():
print('debug: func =', func.__name__)
return func()
return wrapper
@debug
def add(l, r):
return l+r
@debug
def sub(l, r):
return l-r
print('add(1,2) returned', add(1,2))
print('sub(1,2) returned', sub(1,2))
$ python code/40-debug-starargs-wrong.py
Traceback (most recent call last):
File "code/40-debug-starargs-wrong.py", line 15, in <module>
print('add(1,2) returned', add(1,2))
TypeError: wrapper() takes 0 positional arguments but 2 were given
|
|
def debug(func):
def wrapper(*args, **kwargs):
print('debug: func =', func.__name__, args, kwargs)
return func(*args, **kwargs)
return wrapper
@debug
def add(l, r):
return l+r
@debug
def sub(l, r):
return l-r
print('add(1,2) returned', add(1,2))
print('sub(1,2) returned', sub(1,2))
$ python code/45-debug-starargs-right.py
debug: func = add (1, 2) {}
add(1,2) returned 3
debug: func = sub (1, 2) {}
sub(1,2) returned -1
|
|
Sideway: functools.wraps
¶
def debug(func):
def wrapper(*args, **kwargs):
print('debug: func =', func.__name__, args, kwargs)
return func(*args, **kwargs)
return wrapper
@debug
def add(l, r):
return l+r
@debug
def sub(l, r):
return l-r
print('add name:', add.__name__)
print('sub name:', sub.__name__)
$ python code/50-wrapper-name-ugly.py
add name: wrapper
sub name: wrapper
|
|
import functools
def debug(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('debug: func =', func.__name__, args, kwargs)
return func(*args, **kwargs)
return wrapper
@debug
def add(l, r):
return l+r
@debug
def sub(l, r):
return l-r
print('add name:', add.__name__)
print('sub name:', sub.__name__)
$ python code/55-wrapper-name-pretty.py
add name: add
sub name: sub
|
|
Class Decorator: debug()
with prefix¶
import functools
def debug(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('debug: func =', func.__name__, args, kwargs)
return func(*args, **kwargs)
return wrapper
@debug
def add(l, r):
return l+r
@debug
def sub(l, r):
return l-r
print('add name:', add.__name__)
print('sub name:', sub.__name__)
$ python code/60-class-decorator.py
wtf: func = add, (1, 2), {}
add(1,2) = 3
gosh: func = sub, (1, 2), {}
sub(1,2) = -1
|
|