4.7 KiB
[Index](index.md) | [Exercise 5.6](ex5_6.md) | [Exercise 6.2](ex6_2.md)
Exercise 6.1
Objectives:
- Learn more about function argument passing conventions
Files Created: structure.py, stock.py
IMPORTANT NOTE
This exercise is going to start a long road of rewriting the stock.py file in a more
sane way. Before doing anything, copy your work in stock.py to a new file
orig_stock.py.
We're going to recreate the Stock class from scratch using some new techniques.
Make sure you have your unit tests from link:ex5_4.html[Exercise 5.4] handy. You'll want those.
If you define a function, you probably already know that it can be called using a mix of positional or keyword arguments. For example:
>>> def foo(x, y, z):
return x + y + z
>>> foo(1, 2, 3)
6
>>> foo(1, z=3, y=2)
6
>>>
You may also know that you can pass sequences and dictionaries as function arguments using the * and ** syntax. For example:
>>> args = (1, 2, 3)
>>> foo(*args)
6
>>> kwargs = {'y':2, 'z':3 }
>>> foo(1,**kwargs)
6
>>>
In addition to that, you can write functions that accept any number of positional or keyword arguments using the * and ** syntax. For example:
>>> def foo(*args):
print(args)
>>> foo(1,2)
(1, 2)
>>> foo(1,2,3,4,5)
(1, 2, 3, 4, 5)
>>> foo()
()
>>>
>>> def bar(**kwargs):
print(kwargs)
>>> bar(x=1,y=2)
{'y': 2, 'x': 1}
>>> bar(x=1,y=2,z=3)
{'y': 2, 'x': 1, 'z': 3}
>>> bar()
{}
>>>
Variable argument functions are sometimes useful as a technique for reducing or simplifying the amount of code you need to type. In this exercise, we'll explore that idea for simple data structures.
(a) Simplified Data Structures
In earlier exercises, you defined a class representing a stock like this:
class Stock:
def __init__(self,name,shares,price):
self.name = name
self.shares = shares
self.price = price
Focus on the __init__() method---isn't that a lot of
code to type each time you want to populate a structure? What if you
had to define dozens of such structures in your program?
In a file structure.py, define a base class
Structure that allows the user to define simple
data structures as follows:
class Stock(Structure):
_fields = ('name','shares','price')
class Date(Structure):
_fields = ('year', 'month', 'day')
The Structure class should define an __init__()
method that takes any number of arguments and which looks for the
presence of a _fields class variable. Have the method
populate the instance from the attribute names in _fields
and values passed to __init__().
Here is some sample code to test your implementation:
>>> s = Stock('GOOG',100,490.1)
>>> s.name
'GOOG'
>>> s.shares
100
>>> s.price
490.1
>>> s = Stock('AA',50)
Traceback (most recent call last):
...
TypeError: Expected 3 arguments
>>>
(b) Making a Useful Representation
Modify the Structure class so that it produces a nice
representation when repr() is used. For example:
>>> s = Stock('GOOG', 100, 490.1)
>>> s
Stock('GOOG',100,490.1)
>>>
(c) Restricting Attribute Names
Give the Structure class a __setattr__() method that restricts
the allowed set of attributes to those listed in the _fields variable.
However, it should still allow any "private" attribute (e.g., name starting
with _ to be set).
For example:
>>> s = Stock('GOOG',100,490.1)
>>> s.shares = 50
>>> s.share = 50
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "structure.py", line 13, in __setattr__
raise AttributeError('No attribute %s' % name)
AttributeError: No attribute share
>>> s._shares = 100 # Private attribute. OK
>>>
(d) Starting Over
Create a new file stock.py (or delete all of your previous code). Start over by defining Stock as follows:
# stock.py
from structure import Structure
class Stock(Structure):
_fields = ('name', 'shares', 'price')
@property
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares
Once you've done this, run your teststock.py unit tests. You should get a lot of failures, but at least a
handful of the tests should pass.
[Solution](soln6_1.md) | [Index](index.md) | [Exercise 5.6](ex5_6.md) | [Exercise 6.2](ex6_2.md)
>>> Advanced Python Mastery
... A course by dabeaz
... Copyright 2007-2023
. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License