Mais conteúdo relacionado Semelhante a The Power of Decorators in Python [Meetup] (20) Mais de Haim Michael (20) The Power of Decorators in Python [Meetup]1. Decorators in Python
Haim Michael
May 19th
, 2020
All logos, trade marks and brand names used in this presentation belong
to the respective owners.
3. © 2020 life michael
Introduction
The decorator allows us to add new functionality to existing
object without modifying its structure.
When decorating a function, the decoration is invoked
before the definition of the function takes place.
@decorator
def decorated(): pass
is indirectly changed into
decorator(decorated)
4. © 2020 life michael
Jump Start
The simples way to develop a decorator would be to
develop a function that has one parameter to which a
function is passed over.
Whenever our decorator is invoked (enough to have in our
code @ourdecorator to invoke the decorator) the decorated
function will be passed over to our decorator.
5. © 2020 life michael
Jump Start
The decorator function should include the definition of
another function, the decorator function returns. That other
inner function usually invokes the decorated function.
The function returned by our decorator will take the place of
the decorated function. Every call to the decorated function
in our code will be replaced by a call to the function returned
by our decorator.
6. © 2020 life michael
Jump Start
def uppercase(func):
print("2")
def inner():
print("4")
data = func()
return data.upper()
return inner
print("9")
@uppercase
def getGreeting():
print("13")
return "good morning"
print("16")
print(getGreeting())
7. © 2020 life michael
Decorating Function with Parameters
In order to decorate a function with parameter(s) we just
need make sure the function returned by the decorator has
the same parameter(s) accordingly.
8. © 2020 life michael
Decorating Function with Parameters
def uppercase(func):
print("2")
def inner(nickname):
print("4")
data = func(nickname)
return data.upper()
return inner
print("9")
@uppercase
def getGreeting(nickname):
print("13")
return "good morning " + nickname
print("16")
print(getGreeting("dave"))
9. © 2020 life michael
Using a Class as Decorator
The decorator should be a callable object. It can be a
function. I can also be a class we define together with the
__init__ and the __call__.
10. © 2020 life michael
Using a Class as Decorator
class uppercase:
def __init__(self, f):
self.f = f
def __call__(self, nickname):
return self.f(nickname).upper()
@uppercase
def greet(nickname):
return "good morning " + nickname
print(greet("danny"))
11. © 2020 life michael
Decorators Nesting
We can place together more than one decorator. Doing so,
we should imagine the decorators execution one after the
other in the order in which they are listed (top to bottom).
The output of each decorator execution is the input for the
decorator above.
12. © 2020 life michael
Decorators Nesting
def uppercase(func):
def inner(nickname):
data = func(nickname)
return data.upper()
return inner
def stars(func):
def inner(text):
input = func(text)
return "*** "+input+" ***"
return inner
@stars
@uppercase
def getGreeting(nickname):
return "good morning " + nickname
print(getGreeting("dave"))
13. © 2020 life michael
Class Decorators
We can develop a decorator for classes. The object that
represents a class is also a factory function that is called
whenever a new object is created.
def bang(func):
def inner():
print("bang!!!")
ob = func()
return ob
return inner
@bang
class Rectangle(): pass
ob1 = Rectangle()
ob2 = Rectangle()
14. © 2020 life michael
Decorators with Arguments
We can develop a decorator that takes arguments when
called.
def bang(text):
def f(func):
def inner():
print(text)
ob = func()
return ob
return inner
return f
@bang(text="Picaso")
def Rectangle(): pass
ob1 = Rectangle()
ob2 = Rectangle()
15. © 2020 life michael
Stateful Decorators
We can develop a decorator that keeps tracking of a state
by using attributes we add to the object that represents the
decorator.
def counter(text):
if not hasattr(counter,"classes"):
counter.classes = dict()
if text not in counter.classes:
counter.classes[text] = 0
def f(func):
def inner():
counter.classes[text] = int(counter.classes[text]) + 1
ob = func()
return ob
return inner
return f
16. © 2020 life michael
Stateful Decorators
@counter("Rectangle")
class Rectangle(): pass
@counter("Circle")
class Circle(): pass
rec1 = Rectangle()
rec2 = Rectangle()
rec3 = Rectangle()
circ1 = Circle()
circ2 = Circle()
print(counter.classes["Rectangle"])
print(counter.classes["Circle"])
18. © 2020 life michael
Measuring Execution Time
We can easily develop a decorator for the purpose of
measuring the execution time of specific functions.
import time
def stopper(func):
def inner(times):
start = time.perf_counter()
value = func(times)
end = time.perf_counter()
run = end - start
print("running_time=",run)
return value
return inner
@stopper
def doSomething(times):
total = 0
for i in range(times):
total += i
return total
doSomething(99999)
19. © 2020 life michael
Debugging & Logging
We can easily develop a decorator that will track each and
every execution of a specific function.
def tinylog(func):
def f(*args, **kwargs):
args1 = [repr(a) for a in args]
args2 = [repr(k)+":"+repr(v) for k, v in kwargs.items()]
value = func(*args, **kwargs)
print("calling ", func.__name__, " ", repr(args1), " ",
repr(args2), " returns ", value)
return value
return f
@tinylog
def total(a,b):
return a+b
print(total(3,4))
print(total(5,5))
print(total(8,7))
20. © 2020 life michael
Libraries Development
We can easily create decorators for functions and classes
as part of a library for other developers.
There are many libraries that employ the power of
decorators in their service, including ORM libraries (e.g.
PonyORM), Unit Testing libraries (e.g. Testify) and others.
21. © 2020 life michael
Caching Data
Assuming that we have a function that fetches data from the
server we can develop a decorator that will provide us with
an caching mechanism.
22. © 2020 life michael
Questions & Answers
Thanks for attending this meetup.