Initial commit
This commit is contained in:
137
Exercises/ex7_1.md
Normal file
137
Exercises/ex7_1.md
Normal file
@@ -0,0 +1,137 @@
|
||||
\[ [Index](index.md) | [Exercise 6.5](ex6_5.md) | [Exercise 7.2](ex7_2.md) \]
|
||||
|
||||
# Exercise 7.1
|
||||
|
||||
*Objectives:*
|
||||
|
||||
- Learn how to define a simple decorator functions.
|
||||
|
||||
*Files Created:* `logcall.py`
|
||||
|
||||
*Files Modifie:* `validate.py`
|
||||
|
||||
## (a) Your First Decorator
|
||||
|
||||
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:
|
||||
|
||||
```python
|
||||
# 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:
|
||||
|
||||
```python
|
||||
# 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:
|
||||
|
||||
```python
|
||||
>>> import sample
|
||||
Adding logging to add
|
||||
Adding logging to sub
|
||||
>>> sample.add(3,4)
|
||||
Calling add
|
||||
7
|
||||
>>> sample.sub(2,3)
|
||||
Calling sub
|
||||
-1
|
||||
>>>
|
||||
```
|
||||
|
||||
## (b) A Real Decorator
|
||||
|
||||
In [Exercise 6.6](ex6_6.md), 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:
|
||||
|
||||
```python
|
||||
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:
|
||||
|
||||
```python
|
||||
>>> 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).
|
||||
|
||||
```python
|
||||
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.
|
||||
|
||||
\[ [Solution](soln7_1.md) | [Index](index.md) | [Exercise 6.5](ex6_5.md) | [Exercise 7.2](ex7_2.md) \]
|
||||
|
||||
----
|
||||
`>>>` Advanced Python Mastery
|
||||
`...` A course by [dabeaz](https://www.dabeaz.com)
|
||||
`...` Copyright 2007-2023
|
||||
|
||||
. This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)
|
||||
Reference in New Issue
Block a user