4. Agenda
• Primer
• What is a decorator?
• How do they work?
• Examples
5. Primer
Functions
• Functions in Python are first class members
• They can be passed to other functions and return
new functions
def add(first, second):
return first + second
def partial(func, first):
def wrapper(second):
return func(first, second)
return wrapper
7. Primer
Variable function arguments
• Functions can have variable positional and
keyword arguments via *args and **kwargs
• *args and **kwargs can be packed again and
passed along to another function
def func(*args, **kwargs):
print args
print kwargs
11. What is a decorator?
• Injects code before/after a function call or object
creation
• A callable wrapper around a callable resource
(object that implements __call__ is callable)
• Similar to macros in C/C++ but uses built in
Python syntax and language semantics
12. What is a decorator?
• Can be implemented as a function or a class
• Can be applied to a function or a class
• Functions have an implicit __call__ method which
makes them callable
• Classes must implement a __call__ method to
qualify as a decorator
13. How do they work?
Decorator function
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
14. How do they work?
Decorator function
>>> my_function()
in wrapper()
in my_function()
15. How do they work?
Decorator function
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
16. How do they work?
Decorator function
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
17. How do they work?
Decorator function
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
18. How do they work?
Decorator function
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
19. How do they work?
Decorator function
wrapper is a closure over func
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
20. How do they work?
Decorator function
def decorator(func):
def wrapper():
print 'in wrapper()'
return func()
return wrapper
@decorator
def my_function():
print 'in my_function()'
21. How do they work?
Decorator class
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self):
print 'in __call__()'
return self.func()
@Decorator
def my_function():
print 'in my_function()'
22. How do they work?
Decorator class
>>> my_function()
in __call__()
in my_function()
23. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
24. How do they work?
Decorator function with arguments
>>> my_function()
in wrapper()
(1,)
{'config': 'value'}
in my_function()
25. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
26. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
27. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
28. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
29. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
30. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
31. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
32. How do they work?
Decorator function with arguments
def decorator(*args, **kwargs):
def receiver(func):
def wrapper():
print 'in wrapper()'
print args
print kwargs
return func()
return wrapper
return receiver
@decorator(1, config='value')
def my_function():
print 'in my_function()'
33. How do they work?
Decorator class with arguments
class Decorator(object):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __call__(self, func):
def wrapper():
print 'in __call__()'
print self.args
print self.kwargs
return func()
return wrapper
@Decorator(1, config='value')
def my_function():
print 'in my_function()'
34. How do they work?
Decorator class with arguments
>>> my_function()
in __call__()
(1,)
{'config': 'value'}
in my_function()
37. Example: memoize
class Memoize(object):
def __init__(self, func):
self.cache = {}
self.func = func
def __call__(self, *args, **kwargs):
cache_key = '%s%s' % (args, kwargs)
if cache_key in self.cache:
return self.cache[cache_key]
else:
result = self.func(*args, **kwargs)
self.cache[cache_key] = result
return result
@Memoize
def function(bound):
sum = 0
for x in range(bound):
sum += x
return sum