0% found this document useful (0 votes)
16 views21 pages

Decorators

The document provides an overview of Python decorators, explaining their syntax and functionality, including examples of how to create and use them. It covers various types of decorators, including those for functions, class methods, and classes, as well as built-in decorators in the Python Standard Library. The document emphasizes that while decorators are easy to use, they can be complex to write.

Uploaded by

faizafoudhaili
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views21 pages

Decorators

The document provides an overview of Python decorators, explaining their syntax and functionality, including examples of how to create and use them. It covers various types of decorators, including those for functions, class methods, and classes, as well as built-in decorators in the Python Standard Library. The document emphasizes that while decorators are easy to use, they can be complex to write.

Uploaded by

faizafoudhaili
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

5

1 2

4 17032
your AU ID
 Students (lecturers, TAs, ...) can poste multiple-choice questions
together with answer options and explanations
 Students (and others) can
• try to answer questions
• add comments to questions
• grade the quality and difficulty of questions
 Questions can be sorted by e.g. rating, difficulty, #answers, ...
 Activity on PeerWise releases badges
Basic programming
Course overview Advanced / specific python
Libraries & applications

1. Introduction to Python 10. Functions as objects 19. Linear programming


2. Python basics / if 11. Object oriented programming 20. Generators, iterators, with
3. Basic operations 12. Class hierarchies 21. Modules and packages
4. Lists / while / for 13. Exceptions and files 22. Working with text
5. Tuples / comprehensions 14. Doc, testing, debugging 23. Relational data
6. Dictionaries and sets 15. Decorators 24. Clustering
7. Functions 16. Dynamic programming 25. Graphical user interfaces (GUI)
8. Recursion 17. Visualization and optimization 26. Java vs Python
9. Recursion and Iteration 18. Multi-dimensional data 27. Final lecture
10 handins
1 final project (last 1 month)
Decorators
 @

www.python.org/dev/peps/pep-0318/
Python decorators are just syntatic sugar

Python Python
@dec2 def func(arg1, arg2, ...):
@dec1
def func(arg1, arg2, ...):
≡ pass

pass func = dec2(dec1(func))

'pie-decorator' syntax
dec1, dec2, ... are functions (decorators) taking a function as an argument
and returning a new function
Note: decorators are listed bottom up in order of execution
Recap functions
x
5

+
x+y
y 8
3

list
['defg', 'ij', 'abc'] sorted list

len
key function sorted ['ij', 'abc', 'defg']

original decorated
function decorator function
Contrived example : Plus one (I-II)
plus_one1.py plus_one2.py
def plus_one(x): def plus_one(x):
return x + 1 return x + 1

def square(x): def square(x):


return x ** 2 return plus_one(x ** 2)

def cube(x): def cube(x):


return x ** 3 return plus_one(x ** 3)

print(plus_one(square(5))) print(square(5))
print(plus_one(cube(5))) print(cube(5))
Python shell Python shell
| 26 | 26
| 126 | 126
Assume we always need to call plus_one on the We could call plus_one inside functions
result of square and cube (don’t ask why!)
Contrived example : Plus one (III-IV)
plus_one3.py plus_one4.py
def plus_one(x): def plus_one(x):
return x + 1 return x + 1
def square(x): def plus_one_decorator(f):
return x ** 2 return lambda x: plus_one(f(x))
def cube(x): def square(x):
return x ** 3 return x ** 2
square_original = square def cube(x):
cube_original = cube return x ** 3
square = lambda x: plus_one(square_original(x)) square = plus_one_decorator(square)
cube = lambda x: plus_one(cube_original(x)) cube = plus_one_decorator(cube)
print(square(5)) print(square(5))
print(cube(5)) print(cube(5))
Python shell Python shell
| 26 | 26
| 126 | 126
Overwrite square and cube with decorated versions Create a decorator function plus_one_decorator
Contrived example : Plus one (V-VI)
plus_one5.py plus_one6.py
def plus_one(x): def plus_one_decorator(f):
return x + 1 def plus_one(x):
def plus_one_decorator(f): return f(x) + 1
return lambda x: plus_one(f(x)) return plus_one
@plus_one_decorator @plus_one_decorator
def square(x): def square(x):
return x ** 2 return x ** 2
@plus_one_decorator @plus_one_decorator
def cube(x): def cube(x):
return x ** 3 return x ** 3
print(square(5)) print(square(5))
print(cube(5)) print(cube(5))
Python shell Python shell
| 26 | 26
| 126 | 126
Use Python decorator syntax Create local function instead of using lambda
Contrived example : Plus one (VII)
plus_one7.py
def plus_one_decorator(f):
def plus_one(x):
return f(x) + 1
return plus_one
@plus_one_decorator
@plus_one_decorator
def square(x):  A function can have an
return x ** 2 arbitrary number of decorators
@plus_one_decorator
@plus_one_decorator
(also the same repeated)
@plus_one_decorator
def cube(x):
return x ** 3
print(square(5))
print(cube(5))
Python shell
| 27
| 128
Handling arguments run_twice2.py
def run_twice(f):
def wrapper(*args):
run_twice1.py f(*args)
f(*args)
def run_twice(f):
def wrapper(): return wrapper
f() @run_twice
f() def hello_world():
return wrapper print("Hello world")

@run_twice @run_twice
def hello_world(): def hello(txt):
print("Hello world") print("Hello", txt)

hello_world() hello_world()
hello(“Mars")
Python shell
Python shell
| Hello world
| Hello world | Hello world
| Hello world
| Hello Mars
”wrapper” is a common name for the | Hello Mars
function returned by a decorator
args holds the arguments in a tuple
given to the function to be decorated
Question – What does the decorated program print ?
decorator_quizz.py
def double(f):
def wrapper(*args):  7
return 2 * f(*args)
return wrapper  10
def add_three(f):  14
def wrapper(*args):
return 3 + f(*args)
 17
return wrapper  20
@double  Don’t know
@add_three
def seven():
return 7

print(seven())
integer_sum1.py
def integer_sum(*args):
assert all([isinstance(x, int) for x in args]),\

Example: "all arguments most be int"


return sum(args)
Python shell
Enforcing > integer_sum(1, 2, 3, 4)
| 10

argument > integer_sum(1, 2, 3.2, 4)


| AssertionError: all arguments most be int

types integer_sum2.py
def enforce_integer(f): # decorator function
def wrapper(*args):
assert all([isinstance(x, int) for x in args]),\
"all arguments most be int"
 Defining decorators can return f(*args)
return wrapper
be (slightly) complicated @enforce_integer
def integer_sum(*args):
 Using decorators is easy return sum(args)
Python shell
> integer_sum(1, 2, 3, 4)
| 10
> integer_sum(1, 2, 3.2, 4)
| AssertionError: all arguments most be int
Decorators can take arguments

Python Python
@dec(argA, argB, ...) def func(arg1, arg2, ...):
def func(arg1, arg2, ...):
pass
≡ pass
func = dec(argA, argB, ...)(func)

dec is a function (decorator) that takes a list of arguments and returns a function
(to decorate func) that takes a function as an argument and returns a new function
Example: Generic type enforcing
print_repeated.py
def enforce_types(*decorator_args):
def decorator(f):
def wrapper(*args):
assert len(args) == len(decorator_args),\
("got %s arguments, expected %s" % (len(args), len(decorator_args)))
assert all([isinstance(x, t) for x, t in zip(args,decorator_args)]),\
"unexpected types"
return f(*args)
return wrapper
return decorator

@enforce_types(str, int) # decorator with arguments


def print_repeated(txt, n):
print(txt * n)
print_repeated("Hello ", 3)
print_repeated("Hello ", "world")
Python shell
| Hello Hello Hello
| AssertionError: unexpected types
Example: A timer decorator
time_it.py
import time
def time_it(f):
def wrapper(*args, **kwargs):
t_start = time.time()
result = f(*args, **kwargs)
t_end = time.time()
Python shell
t = t_end - t_start
print("%s took %.2f sec" % (f.__name__, t)) | The sum is: 499999500000
return result | slow_function took 0.27 sec
return wrapper | The sum is: 1999999000000
| slow_function took 0.23 sec
@time_it | The sum is: 7999998000000
def slow_function(n): | slow_function took 0.41 sec
sum_ = 0 | The sum is: 31999996000000
for x in range(n): | slow_function took 0.81 sec
sum_ += x | The sum is: 127999992000000
print("The sum is:", sum_) | slow_function took 1.52 sec
for i in range(6): | The sum is: 511999984000000
slow_function(1_000_000 * 2**i) | slow_function took 3.12 sec
Built-in @property
 decorator specific for class methods
 allows accessing x.attribute() as x.attribute,
convenient if attribute does not take any arguments (also readonly)
rectangle1.py rectangle2.py
class Rectangle: class Rectangle:
def __init__(self, width, height): def __init__(self, width, height):
self.width = width self.width = width
self.height = height self.height = height

# @property @property
def area(self): def area(self):
return self.width * self.height return self.width * self.height
Python shell Python shell
> r = Rectangle(3, 4) > r = Rectangle(3, 4)
> print(r.area()) > print(r.area)
| 12 | 12
Class decorators

Python Python
@dec2 class A:
@dec1
class A:
≡ pass

pass A = dec2(dec1(A))
@functools.total_ordering (class decorator)
time_it.py
import functools
Automatically creates
<, <=, >, >= if at least
@functools.total_ordering
class Student(): one of the functions
def __init__(self,name, student_id): is implemented and
self.name = name
self.id = student_id == is implemented
def __eq__(self, other):
return (self.name == other.name Python shell
and self.id == other.id)
> donald < grandma
def __lt__(self, other):
my_name = ', '.join(reversed(self.name.split()))
| True
other_name = ', '.join(reversed(other.name.split())) > grandma >= gladstone
return (my_name < other_name | False
or (my_name == other_name and self.id < other.id)) > grandma <= gladstone
donald = Student('Donald Duck', 7) | True
gladstone = Student('Gladstone Gander', 42) > donald > gladstone
grandma = Student('Grandma Duck', 1) | False
Summary
 @decorator_name
 Pyton decorators are just syntatic sugar
 Adds functionality to a function without having to augment each
call to the function or each return statement in the function
 There are decorators for functions, class methods, and classes
 There are many decorators in the Python Standard Library
 Decorators are easy to use
 ...and slightly harder to write

You might also like