[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Advice Criticism on Python App

Jimbo

3/24/2010 12:05:00 AM

I have made a Python App(really script) that will check a stocks
current values from a website & save that data to a SQLite 3 database.

I am looking for any suggestions & criticisms on what I should do
better or anything at all but mainly in these areas:
[QUOTE]
- Correct Python Layout of code
- Correct error checking: Am I catching all my errors or are my
exceptions not specific enough? Should I be using more try excepts
inside my functions?
- Are there any areas where huge errors, bugs etc could occur that I
have not compensated for?
- I am also looking for suggestions on how to write a function better,
so if you think that function is really bad & should be rewritten
completely or something I would really like to hear it.
- Anything else that you see
- Is python meant to be used in the way I have used it? To make a
'semi detailed' app?[/QUOTE]

Any advice criticism would be really helpful.

App:
[CODE]"""
*Stock Data Builder*
Algorithm:
- Search website for stock
- Get website HTML source code
- Search code for target stock data(price,dividends,etc..)
- Add data to text file
"""

import sys
import os
import sqlite3
import datetime
import time
import urllib2

### Global Variables ###
menu = "***Stock Program*** \n\n1. Add a Stock to track \n2. Get
Todays Tracking Data \n3. Exit \nEnter decision: "
target = '<th scope="row" class="row"><a href="/asx/research/
companyInfo.do?by=asxCode&asxCode=%s">%s</a>'
ASXurl = 'http://www.asx.com.au/asx/markets/price...
by=asxCodes&asxCodes='

class stock:
code = ""
purchasePrice = 0
purchaseQuantity = 0
price = [] # list of recent prices
recentBid = [] # list of recent bids for stock
recentOffer = [] # list of recent offers for stock
stockVol = [] # list of stock quantity available on
market
def __init__(self):
""" Default Constructor """
self.code = ""
self.purchasePrice = 0
self.purchaseQuantity = 0

def constructor(self, stockCode, purPrice, purQuant):
""" Constructor """
self.code = stockCode
self.purchasePrice = purPrice
self.purchaseQuantity = purQuant

def setData(self, stockCode, purPrice, purQuant, priceList,
reBidList, reOffList, popList):
""" Defines & implements the objects' public variables """
self.code = stockCode
self.purchasePrice = purPrice
self.purchaseQuantity = purQuant
self.price = priceList
self.recentBid = reBidList
self.recentOffer = reOffList
self.stockVol = popList

self.printStats()

def updateData(self, priceEle, bidEle, offerEle, populEle):
""" Adds data to stock object's lists """
self.price.append(priceEle)
self.recentBid.append(bidEle)
self.recentOffer.append(offerEle)
self.stockVol.append(populEle)

def printStats(self):
""" Output Stock attributes """

print("Stock Code: "+self.code)
print("Stock Purchase Price: "+str(self.purchasePrice))
print("Stock Quantity Owned: "+str(self.purchaseQuantity))
print("***Initial Investment Value:
"+str(self.purchasePrice*self.purchaseQuantity))
if not(len(self.price) <= 0):
print("Stock Current Price: "+str(self.price[-1]))
print("Recent Bid: "+str(self.recentBid[-1]))
print("Recent Offer: "+str(self.recentOffer[-1]))
print("Total Stock Volume in market:
"+str(self.stockVol[-1]))
print("***Present Investment Value:
"+str(self.price[-1]*self.purchaseQuantity))
print("\n")


### Functions ###
def connectDatabase(dbLocation, dbName, tableName):
""" Establish & Return connection to SQLite Database """

try:
if not (os.path.exists(dbLocation)):
os.mkdir(dbLocation) # create folder/dir

os.chdir(dbLocation) # change directory focus to
dbLocation
conn = sqlite3.connect(dbLocation+dbName)
cur = conn.cursor()
try:
createTableQ = "CREATE TABLE IF NOT EXISTS "+tableName
+" (code varchar PRIMARY KEY, purchase_price float, purchase_quantity
float, purchase_date varchar);"
cur.execute(createTableQ)
conn.commit()
except:
pass
return conn
except IOError or OSError:
print "Connection to database failed"
return False

def retrieveStockDatabase(conn, tableName):
""" Read SQLite3 database & extract stock data into StockList """

stockList = []
stockQuery = "select recent_price, recent_offer, recent_bid,
stock_volume from ? ;"
cur = conn.cursor()
cur.execute("select code, purchase_price, purchase_quantity from
"+tableName+";")

for row in cur.fetchall():
newStock = stock()
newStock.code = row[0]
newStock.purchasePrice = row[1]
newStock.purchaseQuantity = row[2]
cur.execute(stockQuery,[newStock.code])
for rw in cur.fetchall():
newStock.price.append(rw[0])
newStock.recentOffer.append(rw[1])
newStock.recentBid.append(rw[2])
newStock.stockVol.append(rw[3])
stockList.append(newStock)

return stockList

def getDate():
""" Return todays date in format DD:MM:YYYY """
time = datetime.datetime.now()
date = time.strftime("%d:%m:%Y") # string format time (%y)
return date

def newStockDatabase(conn, stockTable, stock):
""" Add a new stock to SQLite database if not already there
We save the stocks code, purchase price, quantity purchased
& date of purchase. """
cur = conn.cursor()
try:
createTableQ = "create table "+stock.code+" (date varchar
PRIMARY KEY, recent_price float, recent_offer float, recent_bid float,
stock_volume double);"
stockQuery = "insert into "+stockTable+"
values(?, ?, ?, ?);"
cur.execute(createTableQ)
cur.execute(stockQuery,
[stock.code,stock.purchasePrice,stock.purchaseQuant,getDate()])
conn.commit()
except IOError or OSError:
print "Table may already exist or bad SQLite connection."
return False

def webFormat(URL):

if (URL.startswith("http://")==False):
URL = "http://"+URL

return URL

def getSource(URL):
""" Retrieve HTML source code from website URL &
save in sourceBuffer """

try:
URL = webFormat(URL) # make sure URL contains essential
"http://"
sourceBuffer = urllib2.urlopen(URL)
print '\nResponse code = ',sourceBuffer.code
print 'Response headers = ',sourceBuffer.info()
print 'Actual URL = ',sourceBuffer.geturl()
sourceCode = sourceBuffer.read()
sourceBuffer.close()
return sourceCode

except IOError: # URLError
print "Function Failed: Reasons could be invalid URL name \nOR
\nHTML protocol message transfer failure."
return False # function failed

def getTargetText(targetStrtData, targetEndData, dataBuffer):
""" Grabs target text that lies inside 'dataBuffer' string
between targetStrtData & targetEndData """

try:
result = dataBuffer.split(targetStrtData)
result.pop(0)
result = result[0].split(targetEndData)
result.pop(1)
print result
return result
except IOError:
print "Function Failed: Reasons could be targetStrtData and/or
targetEndData is not present in dataBuffer."

def getStockData(htmlText, selectedStock):
""" Extract stock data(stock code,price,etc) from htmlText """
try:
# Here I extract my number data from HTML text
tempList = []
for string in htmlText:
for i in string.split('>'):
for e in i.split():
if ('.' in e and e[0].isdigit()):
tempList.append(float(e))
elif (',' in e and e[0].isdigit() ):
# remove ',' chars
e = e.replace(',','')
tempList.append(float(e))


selectedStock.updateData(tempList[0],tempList[2],tempList[3],tempList[7])

except IOError: # is this the correct error I should be trying to
catch here??
print "Function Failed: Reasons could be: sites HTML data has
changed. Consult author of program."
return False

def createStockTracker(stockCode,stockPrice,stockQuant, stockList):
""" Add a new stock to the database to track """
newStock = stock()
newStock.constructor(stockCode,stockPrice,stockQuant)
stockList.append(newStock)
return stockList

def writeStockToDatabase(conn, stock):
""" Write ONLY this Stock's attributes to SQLite Database """

cur = conn.cursor()
date = getDate()

tableName = stock.code
stockquery = "insert into "+tableName+" values(?, ?, ?, ?, ?);"
cur.execute(query,[date,stock.price[-1], stock.recentOffer[-1],
stock.recentBid[-1], stock.stockVol[-1]])
conn.commit()

def writeAllToDatabase(conn, stockList):
""" Enter recent Stock attributes into SQLite Database """

cur = conn.cursor()
date = getDate()

for stock in stockList:
tableName = stock.code
stockquery = "insert into "+tableName+"
values(?, ?, ?, ?, ?);"
cur.execute(query,[date,stock.price[-1],
stock.recentOffer[-1], stock.recentBid[-1], stock.stockVol[-1]])
conn.commit()

### Input Functions ###
def inputNewStock():
""" """
print "*Please note only an Australian Securities Exchange(ASX)
listed stock can be tracked in Version 1.0."
badInput = True

while (badInput == True):
try:
code = raw_input("Please enter the ASX code for the
stock you wish to track: ")
price = input("Please enter the individual stock value
for "+code+": ")
quantity = input("Please enter the number/quantity of
stocks purchased: ")
if (len(code)>3):
badInput = True
else : badInput = False
return True
except IOError:
if (raw_input("Incorrect input. Note: ASX code cannot be
more than 3 chars. Press 'x' to exit or anything else to try
again")=='x'):
return False
badInput = True # this I am not sure if necessary to loop
correctly


### Main program loop ###
def main():
programEnd = False;
dbLocation = "C:\Users\Sam\Desktop\StockApp/"
dbName = "stockData.db"
stockTable = "stocks"

conn = connectDatabase(dbLocation,dbName,stockTable)
stockList = retrieveStockDatabase(conn,stockTable)

for s in stockList:
s.printStats()

while (programEnd == False):

decision = input(menu) # Print Menu

if (decision==1):

if not(inputNewStock()==False):
stockList =
createStockTracker(acode,price,quantity,stockList)
newStockDatabase(conn,stockTable,stockList[-1])
print("\n** New Stock **")
stockList[-1].printStats()
print "The stock "+code+" was successfully added to
our database. \nNow every time the program runs it will automatically
track this stock & obtain its stock attributes\n\n"
# TO DO:
# get new stock recent Data from internet etc.
# add stock data to data base;
elif (decision==2):
if (len(stockList)>0):
for Stock in stockList:
URL = ASXurl+Stock.code
sourceCode = getSource(URL)
targetData = getTargetText(target %
(Stock.code,Stock.code),"</tr>",sourceCode)
getStockData(targetData,Stock)
Stock.printStats()
#writeStockToDatabase(conn,Stock)
else:
print "You must first identify a stock to follow.
\nPlease select option 1."
elif (decision==3):
print "Thank you for using Stock Program. Goodbye.\n"
programEnd = True; # Exit program

conn.close()
return 0 # End program

main()[/CODE]
6 Answers

Chris Rebert

3/24/2010 1:32:00 AM

0

On Tue, Mar 23, 2010 at 5:05 PM, Jimbo <nilly16@yahoo.com> wrote:
> I have made a Python App(really script) that will check a stocks
> current values from a website & save that data to a SQLite 3 database.
>
> I am looking for any suggestions & criticisms on what I should do
> better or anything at all but mainly in these areas:
<snip>
> Any advice criticism would be really helpful.

Complying with Python naming conventions would be one place to start:
* Class names should be in StudlyCaps (so class "Stock", not class "stock").
* Constants should be in UPPERCASE_WITH_UNDERSCORES.
* Most other names should be words_separated_by_underscores, not
camelCaseLikeThis; FWIW, I'm not a fan of this part of the guideline
personally.

Also, conditions don't need parentheses around them. So:
if (decision == 1): #WRONG! harder to read, extra syntactic noise
if decision == 1: #RIGHT

For many more style details, see PEP 8 -- Style Guide for Python Code:
http://www.python.org/dev/peps...

Additionally, the "return 0" in main() serves no purpose; the return
value isn't used as the exit code for the program. You can either
eliminate the line entirely or use plain "return" if you want the
extra clarity.

Cheers,
Chris
--
http://blog.re...

MRAB

3/24/2010 1:37:00 AM

0

Jimbo wrote:
> I have made a Python App(really script) that will check a stocks
> current values from a website & save that data to a SQLite 3 database.
>
> I am looking for any suggestions & criticisms on what I should do
> better or anything at all but mainly in these areas:
> [QUOTE]
> - Correct Python Layout of code
> - Correct error checking: Am I catching all my errors or are my
> exceptions not specific enough? Should I be using more try excepts
> inside my functions?
> - Are there any areas where huge errors, bugs etc could occur that I
> have not compensated for?
> - I am also looking for suggestions on how to write a function better,
> so if you think that function is really bad & should be rewritten
> completely or something I would really like to hear it.
> - Anything else that you see
> - Is python meant to be used in the way I have used it? To make a
> 'semi detailed' app?[/QUOTE]
>
> Any advice criticism would be really helpful.
>
> App:
> [CODE]"""
> *Stock Data Builder*
> Algorithm:
> - Search website for stock
> - Get website HTML source code
> - Search code for target stock data(price,dividends,etc..)
> - Add data to text file
> """
>
> import sys
> import os
> import sqlite3
> import datetime
> import time
> import urllib2
>
> ### Global Variables ###
> menu = "***Stock Program*** \n\n1. Add a Stock to track \n2. Get
> Todays Tracking Data \n3. Exit \nEnter decision: "
> target = '<th scope="row" class="row"><a href="/asx/research/
> companyInfo.do?by=asxCode&asxCode=%s">%s</a>'
> ASXurl = 'http://www.asx.com.au/asx/markets/price...
> by=asxCodes&asxCodes='
>
> class stock:
> code = ""
> purchasePrice = 0
> purchaseQuantity = 0
> price = [] # list of recent prices
> recentBid = [] # list of recent bids for stock
> recentOffer = [] # list of recent offers for stock
> stockVol = [] # list of stock quantity available on
> market

This will be variables belonging to the class itself, not instances of
it.

> def __init__(self):
> """ Default Constructor """
> self.code = ""
> self.purchasePrice = 0
> self.purchaseQuantity = 0
>
> def constructor(self, stockCode, purPrice, purQuant):
> """ Constructor """
> self.code = stockCode
> self.purchasePrice = purPrice
> self.purchaseQuantity = purQuant
>
> def setData(self, stockCode, purPrice, purQuant, priceList,
> reBidList, reOffList, popList):
> """ Defines & implements the objects' public variables """
> self.code = stockCode
> self.purchasePrice = purPrice
> self.purchaseQuantity = purQuant
> self.price = priceList
> self.recentBid = reBidList
> self.recentOffer = reOffList
> self.stockVol = popList
>
> self.printStats()
>
> def updateData(self, priceEle, bidEle, offerEle, populEle):
> """ Adds data to stock object's lists """
> self.price.append(priceEle)
> self.recentBid.append(bidEle)
> self.recentOffer.append(offerEle)
> self.stockVol.append(populEle)
>
> def printStats(self):
> """ Output Stock attributes """
>
> print("Stock Code: "+self.code)

In Python 2 'print' is a statement, so it doesn't need its arguments to
be enclosed in (). You could also use Python's string formatting:

print "Stock Code: %s" % self.code

> print("Stock Purchase Price: "+str(self.purchasePrice))
> print("Stock Quantity Owned: "+str(self.purchaseQuantity))
> print("***Initial Investment Value:
> "+str(self.purchasePrice*self.purchaseQuantity))
> if not(len(self.price) <= 0):

'not' has a lower priority than '<=', and this can be simplified anyway:

if len(self.price) > 0:

or even:

if self.price:

because empty containers (eg lists) are treated as False, non-empty ones
as True, by 'if' and 'while' statements.

> print("Stock Current Price: "+str(self.price[-1]))
> print("Recent Bid: "+str(self.recentBid[-1]))
> print("Recent Offer: "+str(self.recentOffer[-1]))
> print("Total Stock Volume in market:
> "+str(self.stockVol[-1]))
> print("***Present Investment Value:
> "+str(self.price[-1]*self.purchaseQuantity))
> print("\n")
>
>
> ### Functions ###
> def connectDatabase(dbLocation, dbName, tableName):
> """ Establish & Return connection to SQLite Database """
>
> try:
> if not (os.path.exists(dbLocation)):
> os.mkdir(dbLocation) # create folder/dir
>
> os.chdir(dbLocation) # change directory focus to
> dbLocation

It's normally easier to use absolute paths instead of changing the
current directory.

> conn = sqlite3.connect(dbLocation+dbName)

It's better to join paths using os.path.join() because that will insert
any directory separators for you.

> cur = conn.cursor()
> try:
> createTableQ = "CREATE TABLE IF NOT EXISTS "+tableName
> +" (code varchar PRIMARY KEY, purchase_price float, purchase_quantity
> float, purchase_date varchar);"
> cur.execute(createTableQ)
> conn.commit()
> except:
> pass

DON'T USE BARE EXCEPTS, especially if you're just going to ignore the
exception. Exceptions can be raised for a variety of reasons, including
one you didn't expect due to bugs, so catch only what you expect.

> return conn
> except IOError or OSError:

The result of:

IOError or OSError

is:

IOError

What you want is:

except (IOError, OSError):

Note: the parentheses are necessary here, otherwise it it would mean
"catch an IOError exception and then bind it to the name 'OSError'".

> print "Connection to database failed"
> return False
>
Some times you return the connection, and other times False. A more
usual value than False in such cases is None (unless you're returning
True or False).

> def retrieveStockDatabase(conn, tableName):
> """ Read SQLite3 database & extract stock data into StockList """
>
> stockList = []
> stockQuery = "select recent_price, recent_offer, recent_bid,
> stock_volume from ? ;"
> cur = conn.cursor()
> cur.execute("select code, purchase_price, purchase_quantity from
> "+tableName+";")
>
> for row in cur.fetchall():
> newStock = stock()
> newStock.code = row[0]
> newStock.purchasePrice = row[1]
> newStock.purchaseQuantity = row[2]
> cur.execute(stockQuery,[newStock.code])
> for rw in cur.fetchall():
> newStock.price.append(rw[0])
> newStock.recentOffer.append(rw[1])
> newStock.recentBid.append(rw[2])
> newStock.stockVol.append(rw[3])
> stockList.append(newStock)
>
> return stockList
>
> def getDate():
> """ Return todays date in format DD:MM:YYYY """
> time = datetime.datetime.now()
> date = time.strftime("%d:%m:%Y") # string format time (%y)
> return date
>
> def newStockDatabase(conn, stockTable, stock):
> """ Add a new stock to SQLite database if not already there
> We save the stocks code, purchase price, quantity purchased
> & date of purchase. """
> cur = conn.cursor()
> try:
> createTableQ = "create table "+stock.code+" (date varchar
> PRIMARY KEY, recent_price float, recent_offer float, recent_bid float,
> stock_volume double);"
> stockQuery = "insert into "+stockTable+"
> values(?, ?, ?, ?);"
> cur.execute(createTableQ)
> cur.execute(stockQuery,
> [stock.code,stock.purchasePrice,stock.purchaseQuant,getDate()])
> conn.commit()
> except IOError or OSError:
> print "Table may already exist or bad SQLite connection."
> return False
>
> def webFormat(URL):
>
> if (URL.startswith("http://")==False):
> URL = "http://"+URL
>
Better as:

if not URL.startswith("http://"):

The conditions of 'if' and 'while' statements don't need to enclosed in
parentheses like in C, Java, etc.

> return URL
>
> def getSource(URL):
> """ Retrieve HTML source code from website URL &
> save in sourceBuffer """
>
> try:
> URL = webFormat(URL) # make sure URL contains essential
> "http://"
> sourceBuffer = urllib2.urlopen(URL)
> print '\nResponse code = ',sourceBuffer.code
> print 'Response headers = ',sourceBuffer.info()
> print 'Actual URL = ',sourceBuffer.geturl()
> sourceCode = sourceBuffer.read()
> sourceBuffer.close()
> return sourceCode
>
> except IOError: # URLError
> print "Function Failed: Reasons could be invalid URL name \nOR
> \nHTML protocol message transfer failure."
> return False # function failed
>
> def getTargetText(targetStrtData, targetEndData, dataBuffer):
> """ Grabs target text that lies inside 'dataBuffer' string
> between targetStrtData & targetEndData """
>
> try:
> result = dataBuffer.split(targetStrtData)
> result.pop(0)
> result = result[0].split(targetEndData)
> result.pop(1)
> print result
> return result
> except IOError:
> print "Function Failed: Reasons could be targetStrtData and/or
> targetEndData is not present in dataBuffer."
>
You haven't given a return statement for when there's an error, so it'll
return None. It's probably clearer if you write a function in Python
either as a _function_ which _always_ returns a value or as a
_procedure_ which _never_ returns a value.

In Python the preference is for a function to raise an exception to
indicate an error instead of returning a flag.

> def getStockData(htmlText, selectedStock):
> """ Extract stock data(stock code,price,etc) from htmlText """
> try:
> # Here I extract my number data from HTML text
> tempList = []
> for string in htmlText:
> for i in string.split('>'):
> for e in i.split():
> if ('.' in e and e[0].isdigit()):
> tempList.append(float(e))
> elif (',' in e and e[0].isdigit() ):
> # remove ',' chars
> e = e.replace(',','')
> tempList.append(float(e))
>
>
> selectedStock.updateData(tempList[0],tempList[2],tempList[3],tempList[7])
>
> except IOError: # is this the correct error I should be trying to
> catch here??
> print "Function Failed: Reasons could be: sites HTML data has
> changed. Consult author of program."
> return False
>
> def createStockTracker(stockCode,stockPrice,stockQuant, stockList):
> """ Add a new stock to the database to track """
> newStock = stock()
> newStock.constructor(stockCode,stockPrice,stockQuant)
> stockList.append(newStock)
> return stockList
>
> def writeStockToDatabase(conn, stock):
> """ Write ONLY this Stock's attributes to SQLite Database """
>
> cur = conn.cursor()
> date = getDate()
>
> tableName = stock.code
> stockquery = "insert into "+tableName+" values(?, ?, ?, ?, ?);"
> cur.execute(query,[date,stock.price[-1], stock.recentOffer[-1],
> stock.recentBid[-1], stock.stockVol[-1]])
> conn.commit()
>
> def writeAllToDatabase(conn, stockList):
> """ Enter recent Stock attributes into SQLite Database """
>
> cur = conn.cursor()
> date = getDate()
>
> for stock in stockList:
> tableName = stock.code
> stockquery = "insert into "+tableName+"
> values(?, ?, ?, ?, ?);"
> cur.execute(query,[date,stock.price[-1],
> stock.recentOffer[-1], stock.recentBid[-1], stock.stockVol[-1]])
> conn.commit()
>
> ### Input Functions ###
> def inputNewStock():
> """ """
> print "*Please note only an Australian Securities Exchange(ASX)
> listed stock can be tracked in Version 1.0."
> badInput = True
>
> while (badInput == True):

Better as:

while badInput:

> try:
> code = raw_input("Please enter the ASX code for the
> stock you wish to track: ")

If you assign to a name in a function then that name will be treated as
a local name (variable) unless you say it's global in the function,
therefore 'code', etc, won't been seen outside this function.

> price = input("Please enter the individual stock value
> for "+code+": ")
> quantity = input("Please enter the number/quantity of
> stocks purchased: ")
> if (len(code)>3):
> badInput = True
> else : badInput = False
> return True

This will check the length, setting badInput accordingly, and then
return True.

> except IOError:

I don't see anything in the 'try' block that will raise IOError.

> if (raw_input("Incorrect input. Note: ASX code cannot be
> more than 3 chars. Press 'x' to exit or anything else to try
> again")=='x'):
> return False
> badInput = True # this I am not sure if necessary to loop
> correctly
>
You're not explicitly returning anything from the function when the loop
exits, so it would return None.

>
> ### Main program loop ###
> def main():
> programEnd = False;
> dbLocation = "C:\Users\Sam\Desktop\StockApp/"

If your string contains literal backslashes then use raw strings
instead. Raw strings can end in a backslash, but that shouldn't matter
in the script if you're joining paths together using os.path.join().

> dbName = "stockData.db"
> stockTable = "stocks"
>
> conn = connectDatabase(dbLocation,dbName,stockTable)
> stockList = retrieveStockDatabase(conn,stockTable)
>
> for s in stockList:
> s.printStats()
>
> while (programEnd == False):

Better as:

while not programEnd:

>
> decision = input(menu) # Print Menu

input() is often considered a bad function to use because it's
equivalent to eval(raw_input()), so the user could enter any expression.
It's better to use int(raw_input()) in this case and then catch the
ValueError if what was entered isn't an int.

>
> if (decision==1):
>
> if not(inputNewStock()==False):

A double-negative, equivalent to:

if inputNewStock() != False:

It would be more Pythonic if you had inputNewStock() return the code,
etc, or raise an exception if there was an error. You could then catch
that exception in a 'try' block.

> stockList =
> createStockTracker(acode,price,quantity,stockList)
> newStockDatabase(conn,stockTable,stockList[-1])
> print("\n** New Stock **")
> stockList[-1].printStats()
> print "The stock "+code+" was successfully added to
> our database. \nNow every time the program runs it will automatically
> track this stock & obtain its stock attributes\n\n"
> # TO DO:
> # get new stock recent Data from internet etc.
> # add stock data to data base;
> elif (decision==2):
> if (len(stockList)>0):

Better as:

if stockList:

> for Stock in stockList:
> URL = ASXurl+Stock.code
> sourceCode = getSource(URL)
> targetData = getTargetText(target %
> (Stock.code,Stock.code),"</tr>",sourceCode)
> getStockData(targetData,Stock)
> Stock.printStats()
> #writeStockToDatabase(conn,Stock)
> else:
> print "You must first identify a stock to follow.
> \nPlease select option 1."
> elif (decision==3):
> print "Thank you for using Stock Program. Goodbye.\n"
> programEnd = True; # Exit program
>
> conn.close()
> return 0 # End program
>
'main' is called by the main program and its return value is never used,
so just omit this return statement.

> main()[/CODE]

The recommended standard in Python is for names of classes to be
CamelCase, names of constants to be UPPERCASE_WITH_UNDERSCORES, and
names of everything else to be lowercase_with_underscores.

Tim Roberts

3/25/2010 4:14:00 AM

0

Jimbo <nilly16@yahoo.com> wrote:
>
>class stock:
> code = ""
> purchasePrice = 0
> purchaseQuantity = 0
> price = [] # list of recent prices
> recentBid = [] # list of recent bids for stock
> recentOffer = [] # list of recent offers for stock
> stockVol = [] # list of stock quantity available on
>market

Using lists as class variables is a very good way to create very surprising
bugs. Consider the following:

C:\Dev>type x.py

class test:
check = []
def __init__(self):
self.check.append(1)

x = test()
y = test()
z = test()
print x.check
print y.check
print z.check

C:\Dev>x.py
[1, 1, 1]
[1, 1, 1]
[1, 1, 1]

C:\Dev>

> def __init__(self):
> """ Default Constructor """
> self.code = ""
> self.purchasePrice = 0
> self.purchaseQuantity = 0
>
> def constructor(self, stockCode, purPrice, purQuant):
> """ Constructor """
> self.code = stockCode
> self.purchasePrice = purPrice
> self.purchaseQuantity = purQuant

The "constructor" concept here is not very Pythonic. Why not replace those
both with:

def __init__(self, stockCode="", purPrice=0, purQuant=0):
self.code = stockCode
self.purchasePrice = purPrice
self.purchaseQuantity = purQuant
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Steven D'Aprano

3/25/2010 5:10:00 AM

0

On Wed, 24 Mar 2010 21:14:23 -0700, Tim Roberts wrote:

> Jimbo <nilly16@yahoo.com> wrote:
>>
>>class stock:
>> code = ""
>> purchasePrice = 0
>> purchaseQuantity = 0
>> price = [] # list of recent prices
>> recentBid = [] # list of recent bids for stock
>> recentOffer = [] # list of recent offers for stock
>> stockVol = [] # list of stock quantity available on market
>
> Using lists as class variables is a very good way to create very
> surprising bugs. Consider the following:
[snip]


Don't you think that the class attributes are *supposed* to be shared by
all instances? In that case the behaviour you show is not a bug at all.


--
Steven

Bruno Desthuilliers

3/25/2010 2:02:00 PM

0

Steven D'Aprano a écrit :
> On Wed, 24 Mar 2010 21:14:23 -0700, Tim Roberts wrote:
>
>> Jimbo <nilly16@yahoo.com> wrote:
>>> class stock:
>>> code = ""
>>> purchasePrice = 0
>>> purchaseQuantity = 0
>>> price = [] # list of recent prices
>>> recentBid = [] # list of recent bids for stock
>>> recentOffer = [] # list of recent offers for stock
>>> stockVol = [] # list of stock quantity available on market
>> Using lists as class variables is a very good way to create very
>> surprising bugs. Consider the following:
> [snip]
>
>
> Don't you think that the class attributes are *supposed* to be shared by
> all instances? In that case the behaviour you show is not a bug at all.

Python's class attributes are indeed supposed to be shared - that's even
the whole point of having class attributes.

But this feature has proven to be confusing for newcomers that more
often than not have previous exposure to OOPLs where you do "declare"
your class "schema" at the class level (where Python defines class
attributes).

Now reread the OP's code, and you'll find out he's indeed yet another
victim of this gotcha:

"""
for row in cur.fetchall():
newStock = stock()
newStock.code = row[0]
newStock.purchasePrice = row[1]
newStock.purchaseQuantity = row[2]
cur.execute(stockQuery,[newStock.code])
for rw in cur.fetchall():
newStock.price.append(rw[0])
newStock.recentOffer.append(rw[1])
newStock.recentBid.append(rw[2])
newStock.stockVol.append(rw[3])
stockList.append(newStock)
"""

Tim Roberts

3/27/2010 3:15:00 AM

0

Steven D'Aprano <steven@REMOVE.THIS.cybersource.com.au> wrote:

>On Wed, 24 Mar 2010 21:14:23 -0700, Tim Roberts wrote:
>
>> Jimbo <nilly16@yahoo.com> wrote:
>>>
>>>class stock:
>>> code = ""
>>> purchasePrice = 0
>>> purchaseQuantity = 0
>>> price = [] # list of recent prices
>>> recentBid = [] # list of recent bids for stock
>>> recentOffer = [] # list of recent offers for stock
>>> stockVol = [] # list of stock quantity available on market
>>
>> Using lists as class variables is a very good way to create very
>> surprising bugs. Consider the following:
>
>Don't you think that the class attributes are *supposed* to be shared by
>all instances? In that case the behaviour you show is not a bug at all.

Yes, it occurred to me just after I sent that pot that I had answered a
different question from the one he asked. I SUSPECT that he is using class
variables as a way to initialize members, not as true class variables.

Thanks for clarifying this.
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.