[Tutor] OOPs?
Erik Price
erikprice@mac.com
Sat, 30 Mar 2002 18:16:41 -0500
On Saturday, March 30, 2002, at 04:52 PM, Kirby Urner wrote:
> I'm glad you found the code useful Erik. I learned
> something too. I don't usually code menu loops around
> raw_input, so this helped me explore doing that, and
> I haven't used the shelve module a lot (to achieve
> persistence -- shelve uses pickle and some generic
> dbm, whatever the system supports, in the background).
So, I rewrote your code with extra comments so that I could map what
exactly is going on in this module. I've attached the commented code to
the end of this email, if you have a minute and don't mind reading the
comments and letting me know if any of them are off-base that would be
great -- I've made some assumptions about what some things mean. But
you don't have to if you're busy. (Also, do you need to add the shebang
line to the top of modules, or just executable scripts?)
BUT... despite that, I'm finding that I can't seem to get the code to
work right. I can import 'stocks' because I am firing up the
interpreter from the directory where I keep my homemade (or tutored as
in this case) modules. And I can call the mainmenu() function of the
'stocks' module. Once there, I can call the quit() function just fine.
But it seems that my addstock() function, or perhaps it's my getcode()
function, aren't working right.
If I choose "1", then I am prompted for a stock name and a price --
seems to work great. I enter each. But if I choose "3" to call the
dumphist() function, I am always greeted with the exception message from
the try block in getcode(): "Not a legal code" Then the main menu
comes back again (as expected, since getcode() returned a zero).
So, looking into the getcode() function, I can see that the try block is
failing because the value of 'stockdict[code]' cannot be assigned to the
'stockobj' name. Since I'm assuming my Python (2.2) program is working
fine, it must be due to the lack of a 'stockdict[code]' element in the
stockdict dictionary. So I go and look to see where this is generated,
to see if my code is erroneous there.
Well, sure enough, the stockdict dictionary is assigned its associative
indexes and its values at the end of the addstock() function.
Essentially, the value of the 'code' variable (which is the result of
raw_input()) is used as the index, and the value of the element is a new
instance of the Stock class, with 'code' (the user input), 'price' (the
second user input), 'time' (where did this come from?), and 'asctime()'
provided as arguments to the new instance.
Here is where I've discovered my problem. I'm going to continue with
this email anyway, even though just now in writing it I figured out what
was wrong, so hopefully this lesson will go into the archives and can
help someone else someday (I'm a big fan of being a historian when I
can).
There is no 'time' argument to the Stock class. I mis-typed the code
Kirby posted as I was reading it from my mail reader into my text
editor. I don't like copy and paste for the same reason I don't like
hi-liting textbooks -- too easy, and too easy to miss details. But the
drawbacks are that you can make mistakes, and it looks like I did. I
had written this line as
stockdict[code] = Stock(code, price, time, asctime())
instead of the way I should have written it
stockdict[code] = Stock(code, price, time.asctime())
Now I'm going to correct my error and test the code again....
Yup! It works! I assigned the stock of the company I work for a measly
11 cents per share, and then assigned them an even lower 8 cents per
share, then I dumped the data -- here it is:
[('$0.11', 'Sat Mar 30 18:13:30 2002'), ('$0.08', 'Sat Mar 30 18:13:57
2002')]
Okay, so I should probably save bandwidth by not posting this now but
it's not like there's no value in this, and I still have the questions
from the very top... thanks in advance Kirby (and spending an hour using
this code has really taught me a lot!).
Erik
(The following is the code I was using, including the error [this means
that this code won't work! There's a typo in the addstock() function]:)
#!/usr/bin/python
import time, shelve
class Stock:
"Simple stock class, keeps history using current time"
# the constructor defines some attributes of the instance
def __init__(self, code, price, datetime):
self.code = code
# the history is a dictionary that tracks the instance's
# prices and the datetimes of those prices
self.history = [(price, datetime)]
self.price = price
# the newprice() method adds a new price/datetime to the
# instance's history dictionary
def newprice(self, price, datetime):
self.history.append((price, datetime))
# the showhist() method prints the history of the instance
# (a dictionary)
def showhist(self):
return self.history
def getcode():
"Handle cases where user inputs code we don't have"
# accept a stock code
code = raw_input("Code? > ")
# check to see if stock code is in the dictionary
try:
stockobj = stockdict[code]
# if it can't be done, print an error message and exit
except:
print "Not a legal code"
return 0
# if it is, return the object represented by the 'stockdict[code]'
# element of the dictionary that keeps track of stock objects by code
return stockobj
def addstock():
"Add new stock, any code acceptable"
# accept a stock code
code = raw_input("Code? > ")
# accept a price
price = raw_input("Price? > ")
# assign an instance of the Stock class to 'stockdict[code]'
stockdict[code] = Stock(code, price, time, asctime())
def update():
# assign to 'obj' an instance of the Stock class from getcode()
obj = getcode()
# if a Stock class instance was pulled and assigned to 'obj'
if obj:
# accept a price
price = raw_input("Price? > ")
# call the newprice() method of the instance
obj.newprice(price, time.asctime())
# print the number of items in the instance's history dictionary
print "%s prices on file" % len(obj.history)
# would not have to do next step if using real dictionary
stockdict[obj.code] = obj # overwrites old copy
def dumphist():
# assign to 'obj' an instance of the Stock class from getcode()
obj = getcode()
# if a Stock class instance was pulled and assigned to 'obj'
if obj:
# call the 'showhist()' method of the Stock instance 'obj',
# and assign it to the 'hist' variable
hist = obj.showhist()
# print the value of the 'hist' variable
print hist
def quit():
# call the close() method of the stockdict object
stockdict.close()
print "Stocks saved"
def mainmenu():
"Using dictionary-like syntax to do file i/o"
# globalize the stockdict name
global stockdict
# create a 'stockdict' object and give it the current value
# of 'shelve.open("mystocks")'
stockdict = shelve.open("mystocks")
# create a tuple called 'callables'
callables = [quit, addstock, update, dumphist]
# display the menu
while 1:
print \
"""
(1) add new stock
(2) update price of stock
(3) dump history of stock
(0) save/quit
"""
# accept a selection
sel = raw_input("Your choice: > ")
try:
# make sel an integer
sel = int(sel)
# test that sel is less than or equal to 3
# and greater than or equal to 0
assert int(sel) <= 3 and int(sel) >= 0
# call whichever function is represented by sel
callables[int(sel)]()
if int(sel) == 0:
break
# if the try fails
except:
print "Not a legal choice"