98 lines
2.3 KiB
Markdown
98 lines
2.3 KiB
Markdown
---
|
|
id: practical-python-7.7
|
|
source_exercise_id: "7.7"
|
|
title: "Using Closures to Avoid Repetition"
|
|
section: "7.3 Returning Functions"
|
|
source_path: "07_Advanced_Topics/03_Returning_functions.md"
|
|
source_repo: "https://github.com/dabeaz-course/practical-python"
|
|
source_commit: "93dca856b41c61a0a0f85ae334116e4c125629ea"
|
|
student_visible_solution: false
|
|
has_private_solution: false
|
|
skip: false
|
|
---
|
|
|
|
# Exercise 7.7: Using Closures to Avoid Repetition
|
|
|
|
> Source: Practical Python Programming, `07_Advanced_Topics/03_Returning_functions.md`.
|
|
|
|
### Exercise 7.7: Using Closures to Avoid Repetition
|
|
|
|
One of the more powerful features of closures is their use in
|
|
generating repetitive code. If you refer back to [Exercise
|
|
5.7](../05_Object_model/02_Classes_encapsulation), recall the code for
|
|
defining a property with type checking.
|
|
|
|
```python
|
|
class Stock:
|
|
def __init__(self, name, shares, price):
|
|
self.name = name
|
|
self.shares = shares
|
|
self.price = price
|
|
...
|
|
@property
|
|
def shares(self):
|
|
return self._shares
|
|
|
|
@shares.setter
|
|
def shares(self, value):
|
|
if not isinstance(value, int):
|
|
raise TypeError('Expected int')
|
|
self._shares = value
|
|
...
|
|
```
|
|
|
|
Instead of repeatedly typing that code over and over again, you can
|
|
automatically create it using a closure.
|
|
|
|
Make a file `typedproperty.py` and put the following code in
|
|
it:
|
|
|
|
```python
|
|
# typedproperty.py
|
|
|
|
def typedproperty(name, expected_type):
|
|
private_name = '_' + name
|
|
@property
|
|
def prop(self):
|
|
return getattr(self, private_name)
|
|
|
|
@prop.setter
|
|
def prop(self, value):
|
|
if not isinstance(value, expected_type):
|
|
raise TypeError(f'Expected {expected_type}')
|
|
setattr(self, private_name, value)
|
|
|
|
return prop
|
|
```
|
|
|
|
Now, try it out by defining a class like this:
|
|
|
|
```python
|
|
from typedproperty import typedproperty
|
|
|
|
class Stock:
|
|
name = typedproperty('name', str)
|
|
shares = typedproperty('shares', int)
|
|
price = typedproperty('price', float)
|
|
|
|
def __init__(self, name, shares, price):
|
|
self.name = name
|
|
self.shares = shares
|
|
self.price = price
|
|
```
|
|
|
|
Try creating an instance and verifying that type-checking works.
|
|
|
|
```python
|
|
>>> s = Stock('IBM', 50, 91.1)
|
|
>>> s.name
|
|
'IBM'
|
|
>>> s.shares = '100'
|
|
... should get a TypeError ...
|
|
>>>
|
|
```
|
|
|
|
## 关联来源
|
|
|
|
- [[summaries/03_Returning_functions]]
|