Advice Criticism on Python App


J

Jimbo

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:
- 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?

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/priceLookup.do?
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()
 
Ad

Advertisements

C

Chris Rebert

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:
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/pep-0008/

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
 
M

MRAB

Jimbo said:
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:
- 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?

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/priceLookup.do?
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[/QUOTE]

This will be variables belonging to the class itself, not instances of
it.
[QUOTE]
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)[/QUOTE]

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
[QUOTE]
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):[/QUOTE]

'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.
[QUOTE]
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[/QUOTE]

It's normally easier to use absolute paths instead of changing the
current directory.
[QUOTE]
conn = sqlite3.connect(dbLocation+dbName)[/QUOTE]

It's better to join paths using os.path.join() because that will insert
any directory separators for you.
[QUOTE]
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[/QUOTE]

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.
[QUOTE]
return conn
except IOError or OSError:[/QUOTE]

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'".
[QUOTE]
print "Connection to database failed"
return False
[/QUOTE]
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).
[QUOTE]
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
[/QUOTE]
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.
[QUOTE]
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."
[/QUOTE]
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.
[QUOTE]
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):[/QUOTE]

Better as:

     while badInput:
[QUOTE]
try:
code     = raw_input("Please enter the ASX code for the
stock you wish to track: ")[/QUOTE]

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.
[QUOTE]
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[/QUOTE]

This will check the length, setting badInput accordingly, and then
return True.
[QUOTE]
except IOError:[/QUOTE]

I don't see anything in the 'try' block that will raise IOError.
[QUOTE]
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
[/QUOTE]
You're not explicitly returning anything from the function when the loop
exits, so it would return None.
[QUOTE]
### Main program loop ###
def main():
programEnd = False;
dbLocation = "C:\Users\Sam\Desktop\StockApp/"[/QUOTE]

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().
[QUOTE]
dbName     = "stockData.db"
stockTable = "stocks"

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

for s in stockList:
s.printStats()

while (programEnd == False):[/QUOTE]

Better as:

     while not programEnd:
[QUOTE]
decision = input(menu) # Print Menu[/QUOTE]

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.
[QUOTE]
if (decision==1):

if not(inputNewStock()==False):[/QUOTE]

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.
[QUOTE]
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):[/QUOTE]

Better as:

             if stockList:
[QUOTE]
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
[/QUOTE]
'main' is called by the main program and its return value is never used,
so just omit this return statement.
[QUOTE]
main()

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.
 
S

Steven D'Aprano

Jimbo said:
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.
 
Ad

Advertisements

B

Bruno Desthuilliers

Steven D'Aprano a écrit :
Jimbo said:
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)
"""
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top