Initial commit
This commit is contained in:
170
Exercises/ex3_2.md
Normal file
170
Exercises/ex3_2.md
Normal file
@@ -0,0 +1,170 @@
|
||||
\[ [Index](index.md) | [Exercise 3.1](ex3_1.md) | [Exercise 3.3](ex3_3.md) \]
|
||||
|
||||
# Exercise 3.2
|
||||
|
||||
*Objectives:*
|
||||
|
||||
- Learn about attribute access
|
||||
- Learn how use getattr(), setattr(), and related functions.
|
||||
- Experiment with bound methods.
|
||||
|
||||
|
||||
*Files Created:* `tableformat.py`
|
||||
|
||||
## (a) The Three Operations
|
||||
|
||||
The entire Python object system consists of just three core operations: getting, setting, and deleting
|
||||
of attributes. Normally, these are accessed via the dot (.) like this:
|
||||
|
||||
```python
|
||||
>>> s = Stock('GOOG', 100, 490.1)
|
||||
>>> s.name # get
|
||||
'GOOG'
|
||||
>>> s.shares = 50 # set
|
||||
>>> del s.shares # delete
|
||||
>>>
|
||||
```
|
||||
|
||||
The three operations are also available as functions. For example:
|
||||
|
||||
```python
|
||||
>>> getattr(s, 'name') # Same as s.name
|
||||
'GOOG'
|
||||
>>> setattr(s, 'shares', 50) # Same as s.shares = 50
|
||||
>>> delattr(s, 'shares') # Same as del s.shares
|
||||
>>>
|
||||
```
|
||||
|
||||
An additional function `hasattr()` can be used to probe an object for the existence of an attribute:
|
||||
|
||||
```python
|
||||
>>> hasattr(s, 'name')
|
||||
True
|
||||
>>> hasattr(s, 'blah')
|
||||
False
|
||||
>>>
|
||||
```
|
||||
|
||||
## (b) Using getattr()
|
||||
|
||||
The `getattr()` function is extremely useful for
|
||||
writing code that processes objects in an extremely generic way. To
|
||||
illustrate, consider this example which prints out a set of
|
||||
user-defined attributes:
|
||||
|
||||
```python
|
||||
>>> s= Stock('GOOG', 100, 490.1)
|
||||
>>> fields = ['name','shares','price']
|
||||
>>> for name in fields:
|
||||
print(name, getattr(s, name))
|
||||
|
||||
name GOOG
|
||||
shares 100
|
||||
price 490.1
|
||||
>>>
|
||||
```
|
||||
|
||||
## (c) Table Output
|
||||
|
||||
In link:ex3_1.html[Exercise 3.1], you wrote a function `print_portfolio()`
|
||||
that made a nicely formatted table. That function was custom tailored
|
||||
to a list of `Stock` objects. However, it can be completely generalized
|
||||
to work with any list of objects using the technique in part (b).
|
||||
|
||||
Create a new module called `tableformat.py`. In that program,
|
||||
write a function `print_table()` that takes a sequence (list) of objects,
|
||||
a list of attribute names, and prints a nicely formatted table. For example:
|
||||
|
||||
```python
|
||||
>>> import stock
|
||||
>>> import tableformat
|
||||
>>> portfolio = stock.read_portfolio('Data/portfolio.csv')
|
||||
>>> tableformat.print_table(portfolio, ['name','shares','price'])
|
||||
name shares price
|
||||
---------- ---------- ----------
|
||||
AA 100 32.2
|
||||
IBM 50 91.1
|
||||
CAT 150 83.44
|
||||
MSFT 200 51.23
|
||||
GE 95 40.37
|
||||
MSFT 50 65.1
|
||||
IBM 100 70.44
|
||||
|
||||
>>> tableformat.print_table(portfolio,['shares','name'])
|
||||
shares name
|
||||
---------- ----------
|
||||
100 AA
|
||||
50 IBM
|
||||
150 CAT
|
||||
200 MSFT
|
||||
95 GE
|
||||
50 MSFT
|
||||
100 IBM
|
||||
>>>
|
||||
```
|
||||
|
||||
For simplicity, just have the `print_table()` function print each field in
|
||||
a 10-character wide column.
|
||||
|
||||
## (d) Bound Methods
|
||||
|
||||
It may be surprising, but method calls are layered onto the machinery used
|
||||
for simple attributes. Essentially, a method is an attribute that
|
||||
executes when you add the required parentheses () to call it like a function. For
|
||||
example:
|
||||
|
||||
```python
|
||||
>>> s = Stock('GOOG',100,490.10)
|
||||
>>> s.cost # Looks up the method
|
||||
<bound method Stock.cost of <__main__.Stock object at 0x409530>>
|
||||
>>> s.cost() # Looks up and calls the method
|
||||
49010.0
|
||||
|
||||
>>> # Same operations using getattr()
|
||||
>>> getattr(s, 'cost')
|
||||
<bound method Stock.cost of <__main__.Stock object at 0x409530>>
|
||||
>>> getattr(s, 'cost')()
|
||||
49010.0
|
||||
>>>
|
||||
```
|
||||
|
||||
A bound method is attached to the object where it came from. If that
|
||||
object is modified, the method will see the modifications. You can
|
||||
view the original object by inspecting the `__self__` attribute
|
||||
of the method.
|
||||
|
||||
```python
|
||||
>>> c = s.cost
|
||||
>>> c()
|
||||
49010.0
|
||||
>>> s.shares = 75
|
||||
>>> c()
|
||||
36757.5
|
||||
>>> c.__self__
|
||||
<__main__.Stock object at 0x409530>
|
||||
>>> c.__func__
|
||||
<function cost at 0x37cc30>
|
||||
>>> c.__func__(c.__self__) # This is what happens behind the scenes of calling c()
|
||||
36757.5
|
||||
>>>
|
||||
```
|
||||
|
||||
Try it with the `sell()` method just to make sure you
|
||||
understand the mechanics:
|
||||
|
||||
```python
|
||||
>>> f = s.sell
|
||||
>>> f.__func__(f.__self__, 25) # Same as s.sell(25)
|
||||
>>> s.shares
|
||||
50
|
||||
>>>
|
||||
```
|
||||
|
||||
\[ [Solution](soln3_2.md) | [Index](index.md) | [Exercise 3.1](ex3_1.md) | [Exercise 3.3](ex3_3.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