Introduction
Objectives:
- Learn how to define a simple decorator functions.
Files Created: logcall.py
Files Modifie: validate.py
This tutorial is from open-source community. Access the source code
Objectives:
Files Created: logcall.py
Files Modifie: validate.py
To start with decorators, write a very simple decorator function that simply prints out a message each time a function is called. Create a file logcall.py
and define the following function:
## logcall.py
def logged(func):
print('Adding logging to', func.__name__)
def wrapper(*args, **kwargs):
print('Calling', func.__name__)
return func(*args, **kwargs)
return wrapper
Now, make a separate file sample.py
and apply it to a few function definitions:
## sample.py
from logcall import logged
@logged
def add(x,y):
return x+y
@logged
def sub(x,y):
return x-y
Test your code as follows:
>>> import sample
Adding logging to add
Adding logging to sub
>>> sample.add(3,4)
Calling add
7
>>> sample.sub(2,3)
Calling sub
-1
>>>
Hint: Complete the following in the validate.py
file
In Exercise 6.6, you created a callable class ValidatedFunction
that enforced type annotations. Rewrite this class as a decorator function called validated
. It should allow you to write code like this:
from validate import Integer, validated
@validated
def add(x: Integer, y:Integer) -> Integer:
return x + y
@validated
def pow(x: Integer, y:Integer) -> Integer:
return x ** y
Here's how the decorated functions should work:
>>> add(2, 3)
5
>>> add('2', '3')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "validate.py", line 75, in wrapper
raise TypeError('Bad Arguments\n' + '\n'.join(errors))
TypeError: Bad Arguments
x: Expected <class 'int'>
y: Expected <class 'int'>
>>> pow(2, 3)
8
>>> pow(2, -1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "validate.py", line 83, in wrapper
raise TypeError(f'Bad return: {e}') from None
TypeError: Bad return: Expected <class 'int'>
>>>
Your decorator should try to patch up the exceptions so that they show more useful information as shown. Also, the @validated
decorator should work in classes (you don't need to do anything special).
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
@property
def cost(self):
return self.shares * self.price
@validated
def sell(self, nshares:PositiveInteger):
self.shares -= nshares
Note: This part doesn't involve a lot of code, but there are a lot of low-level fiddly bits. The solution will look almost the same as for Exercise 6.6. Don't be shy about looking at solution code though.
Congratulations! You have completed the Define a Simple Decorator Functions lab. You can practice more labs in LabEx to improve your skills.