help with my first use of a class

B

BartlebyScrivener

I am a mere hobbyist. Spent several hours trying to make a class,
because I think this is an occasion where I need one. But I can't make
it work.

This code "works" (only because of the global c, which I know I'm
supposed to avoid, by using a Class). I edited the rest to leave out
the irrelevant formatting and printing of the quotations.

I've read about Classes several times, but I don't "get" them yet.
Obviously. If I can solve one real life problem like this, then maybe
I'll see the light.

If I understand the power of Classes correctly, I could make one that
would allow me to make a new instance that would connect to, say, an
SQLite3 db instead of the Access db, as well as to create more methods
that will do different SQL searches.

Thank you for any help,

rd

--------------------------------------

import mx.ODBC.Windows as odbc
import sys
import random

def connect():
global c
db='DSN=Quotations'
conn = odbc.DriverConnect(db)
c = conn.cursor()

def random_quote():
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
# Yields the number of rows with something in the quote field
total_quotes = c.fetchone()
# Get a random number somewhere between 1 and the number of total
quotes
quote_number = (random.randint(1, total_quotes[0]),)
# Select a quote where the ID matches that number
c.execute ("SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?",
quote_number)
quote = c.fetchone()
blah blah blah

def print_quote()
code to format and print the quote (which will also have to be
global, unless I learn Classes!)


if __name__ == '__main__':
if len(sys.argv) == 1:
connect()
random_quote()
print_quote()
 
B

BartlebyScrivener

Whoah. At least I got the connection. I think. Maybe I can figure more
on my own. Any help appreciated.

Thanks

---------

class Connection:
def __init__(self, aDatasource):
self.db = aDatasource
self.conn = odbc.DriverConnect(self.db)
self.conn.cursor()

def random_quote():
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c = Connection('DSN=Quotations')
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
 
J

James Stroud

BartlebyScrivener said:
I am a mere hobbyist. Spent several hours trying to make a class,
because I think this is an occasion where I need one. But I can't make
it work.

This code "works" (only because of the global c, which I know I'm
supposed to avoid, by using a Class). I edited the rest to leave out
the irrelevant formatting and printing of the quotations.

I've read about Classes several times, but I don't "get" them yet.
Obviously. If I can solve one real life problem like this, then maybe
I'll see the light.

If I understand the power of Classes correctly, I could make one that
would allow me to make a new instance that would connect to, say, an
SQLite3 db instead of the Access db, as well as to create more methods
that will do different SQL searches.

Thank you for any help,

rd

--------------------------------------

import mx.ODBC.Windows as odbc
import sys
import random

def connect():
global c
db='DSN=Quotations'
conn = odbc.DriverConnect(db)
c = conn.cursor()

def random_quote():
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
# Yields the number of rows with something in the quote field
total_quotes = c.fetchone()
# Get a random number somewhere between 1 and the number of total
quotes
quote_number = (random.randint(1, total_quotes[0]),)
# Select a quote where the ID matches that number
c.execute ("SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?",
quote_number)
quote = c.fetchone()
blah blah blah

def print_quote()
code to format and print the quote (which will also have to be
global, unless I learn Classes!)


if __name__ == '__main__':
if len(sys.argv) == 1:
connect()
random_quote()
print_quote()

You really don't need classes for this, just parameters + return values.
Probably best would be to master the idea of parameters + return values
before yo move on to classes. This is called "procedural" programming.
Notice that there is no name collision because of strict python
namespaces (a good idea, according to Tim Peters).


For example:

def connect():
db='DSN=Quotations'
conn = odbc.DriverConnect(db)
c = conn.cursor()
# NOTE THE RETURN VALUE:
return c

def random_quote(c): # <== NOTE THE PARAMETER
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
# Yields the number of rows with something in the quote field
total_quotes = c.fetchone()
# Get a random number somewhere between 1 and ...
quote_number = (random.randint(1, total_quotes[0]),)
# Select a quote where the ID matches that number
q = "SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?"
c.execute (q, quote_number)
quote = c.fetchone()
# NOTE THE RETURN VALUE:
return quote

def print_quote(quote): # <== NOTE THE PARAMETER
print quote # <== WHATEVER YOU WANT TO DO

if __name__ == '__main__':
if len(sys.argv) == 1:
c = connect() # <== NO COLLISION: NAMESPACES
quote = random_quote(c) # <== DITTO
print_quote(quote) # THERE YOU HAVE IT


James
 
W

wittempj

BartlebyScrivener said:
I am a mere hobbyist. Spent several hours trying to make a class,
because I think this is an occasion where I need one. But I can't make
it work.

This code "works" (only because of the global c, which I know I'm
supposed to avoid, by using a Class). I edited the rest to leave out
the irrelevant formatting and printing of the quotations.

I've read about Classes several times, but I don't "get" them yet.
Obviously. If I can solve one real life problem like this, then maybe
I'll see the light.

If I understand the power of Classes correctly, I could make one that
would allow me to make a new instance that would connect to, say, an
SQLite3 db instead of the Access db, as well as to create more methods
that will do different SQL searches.

Thank you for any help,

rd

--------------------------------------

import mx.ODBC.Windows as odbc
import sys
import random

def connect():
global c

This means you want to use a global variable c which doesn't exist yet,
an example would be to save this code to a file:

#!/usr/bin/env python

c = 0
def test_global():
global c
c = 1

print c

this will print 0 when you run it
db='DSN=Quotations'
conn = odbc.DriverConnect(db)
c = conn.cursor()

def random_quote():
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
# Yields the number of rows with something in the quote field
total_quotes = c.fetchone()
# Get a random number somewhere between 1 and the number of total
quotes
quote_number = (random.randint(1, total_quotes[0]),)
# Select a quote where the ID matches that number
c.execute ("SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?",
quote_number)
quote = c.fetchone()
blah blah blah

def print_quote()
code to format and print the quote (which will also have to be
global, unless I learn Classes!)

A class structure could look like - please bear in mind that I don't
know mx.ODBC.Windows - I guess it is not completely DB-API compliant,
as you don't use a connect method.

class SQLQuery(object):
"""Object which connects to the database and can execurte SQL
commands
"""
def __init__(self, conn):
"""conn is a dictionary {'serverId': XX, 'userId': YY,
'passWord': ZZ}
"""
self.connection = connect(conn['userId'], conn['passWord'],
conn['serverId'])
self.cursor = self.__connection.cursor()

def select(self, selectqry):
"""argument selectqry specifies a sql which returns data, like a
select
"""
self.cursor.execute(selectqry)
return self.cursor.fetchall()

sql = SQLQuery('serverId': 'XX', 'userId': 'YY', 'passWord': 'ZZ')
qoutes = sql.select("SELECT COUNT(Quote) FROM PythonQuoteQuery")
print quotes
if __name__ == '__main__':
if len(sys.argv) == 1:

sys.argv is a list, where the first argument is the name of the running
script, the second element is the first argument, etc.
 
B

BartlebyScrivener

Wow,

That's great, James.

Thanks. I shall put it together.

Appreciate it.

rd
 
D

Dennis Lee Bieber

If I understand the power of Classes correctly, I could make one that
would allow me to make a new instance that would connect to, say, an
SQLite3 db instead of the Access db, as well as to create more methods
that will do different SQL searches.
Not the way I'd do it...

If using a db-api compliant adapter, and using minimal common
features, the main thing one would have to worry about is the different
placeholders used by the adapter.

I'd be more likely to do something like

import <pick-a-db-adapter> as db

and then have a class query the db connection for what type of
placeholder it uses, then modify any queries the class uses.

You might make a "class" for each database /table/, and each
instance of that class would be one record in the table. The class would
have the methods for retrieval/update/delete/insert, when given the key
value, perhaps.
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
B

Bruno Desthuilliers

BartlebyScrivener said:
I am a mere hobbyist. Spent several hours trying to make a class,
because I think this is an occasion where I need one. But I can't make
it work.

This code "works" (only because of the global c, which I know I'm
supposed to avoid, by using a Class). I edited the rest to leave out
the irrelevant formatting and printing of the quotations.

I've read about Classes several times, but I don't "get" them yet.

Think of a class as both a "blueprint" for objects and a factory
creating these objects. The class lets you define the attributes and
behaviors of it's instances.
Obviously. If I can solve one real life problem like this, then maybe
I'll see the light.

If I understand the power of Classes correctly, I could make one that
would allow me to make a new instance that would connect to, say, an
SQLite3 db instead of the Access db, as well as to create more methods
that will do different SQL searches.

Thank you for any help,


import mx.ODBC.Windows as odbc
import sys
import random

def connect():
global c
db='DSN=Quotations'
conn = odbc.DriverConnect(db)
c = conn.cursor()

def random_quote():
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
# Yields the number of rows with something in the quote field
total_quotes = c.fetchone()
# Get a random number somewhere between 1 and the number of total
quotes
quote_number = (random.randint(1, total_quotes[0]),)
# Select a quote where the ID matches that number
c.execute ("SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?",
quote_number)
quote = c.fetchone()
blah blah blah

def print_quote()
code to format and print the quote (which will also have to be
global, unless I learn Classes!)

Ever wondered what arguments and return values were for ?-)
if __name__ == '__main__':
if len(sys.argv) == 1:
connect()
random_quote()
print_quote()

First, notice that you *don't* need a class here to avoid globals.
Learning to use function as *functions* (ie: taking arguments and
returning values) instead of procedure would help:

def random_quote(cursor):
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
total_quotes = c.fetchone()
quote_number = (random.randint(1, total_quotes[0]),)
c.execute (
"SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?",
quote_number
)
return c.fetchone()

def format_quote(quote):
# code here
return formatted_quote

def main(*args):
if len(args) < 2:
print >> sys.stderr, "Missing dsn arg\nusage : %s dsn" % args[0]
return 1
dsn = args[1]
try:
conn = odbc.DriverConnect(dsn)
except <SomeODBCErrorHere>, e:
print >> sys.stderr "Cannot connect to %s : %s" % (dsn, e)
return 1
quote = random_quote(conn.cursor())
print format_quote(quote)
conn.close()
return 0

if __name__ == '__main__':
sys.exit(main(*sys.argv))


Now for an OO version - that won't buy you much IMHO:

class SQLFortune(object):
def __init__(self, dsn):
self._dsn = dsn
self._cnx = None

@apply
def connection():
def fget(self):
if self._cnx is None:
self._cnx = odbc.DriverConnect(self.dsn)
return self._cnx
def fset(self, _):
raise AttributeError("Attribute is read-only")
return property(**locals())

def random_quote(self):
c = self.connection.cursor()
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")
total_quotes = c.fetchone()
quote_number = (random.randint(1, total_quotes[0]),)
c.execute (
"SELECT Author, Quote FROM PythonQuoteQuery WHERE ID=?",
quote_number
)
return c.fetchone()

def format_quote(self, quote):
# code here
return formatted_quote

def close(self):
try: self._cnx.close()
except: pass

def main(*args):
if len(args) < 2:
print >> sys.stderr, "Missing dsn arg\nusage : %s dsn" % args[0]
return 1
dsn = args[1]
fortune = SQLFortune(dsn)
print fortune.format_quote(fortune.random_quote())
fortune.close()
return 0

if __name__ == '__main__':
sys.exit(main(*sys.argv))
 
B

Bruno Desthuilliers

BartlebyScrivener said:
Whoah. At least I got the connection. I think. Maybe I can figure more
on my own. Any help appreciated.

Thanks

---------

class Connection:
def __init__(self, aDatasource):
self.db = aDatasource
self.conn = odbc.DriverConnect(self.db)
self.conn.cursor()

This creates a cursor, that's immediatly discarded.
def random_quote():
"""
Counts all of the quotes in MS Access database Quotations2005.mdb.
Picks one quote at random and displays it using textwrap.
"""
c = Connection('DSN=Quotations')
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")

And this will raise an AttributeError, since your (mostly useless)
Connection class doesn't define an 'execute' method.
 
F

Fredrik Lundh

Bruno said:
First, notice that you *don't* need a class here to avoid globals.
Learning to use function as *functions* (ie: taking arguments and
returning values) instead of procedure would help:

def random_quote(cursor):
c.execute ("SELECT COUNT(Quote) FROM PythonQuoteQuery")

make that "cursor.execute" (etc)

</F>
 
B

BartlebyScrivener

Thank you all!

My main problem is going away from Python and programming for weeks or
months at a time, then picking up where I left off. But Python is much
better in this regard than Perl.

I appreciate the help.

rd
 
F

Fulvio

***********************
Your mail has been scanned by InterScan MSS.
***********************


You really don't need classes for this

I'm in that matter too. Doesn't classes make the main program neater?
Fundamentally OOP is the way to assemble ready objects to get a "thing"
working, rather than worry about any single code line.
Is this a concept of python?

F
 
B

Bruno Desthuilliers

Fulvio said:
***********************
Your mail has been scanned by InterScan MSS.
***********************




I'm in that matter too. Doesn't classes make the main program neater?

Depends on the program.
Fundamentally OOP is the way to assemble ready objects to get a "thing"
working, rather than worry about any single code line.

This is more a wishful dream than reality. While it can effectively be
pretty powerful - specially with dynamic languages like Python or Ruby -
OO is by no mean magical.
Is this a concept of python?

If you mean "a concept specific to Python", well, not really - OO first
reared it's head with Simula in the sixties and matured in the seventies
with Smalltalk (which is still the reference IMHO). And it's (it->OO)
more an evolution/systematisation of concepts that already existed
before...

FWIW, I don't know if there's any truly Python-specific concept in
Python (except perhaps for the descriptor protocol, which is a somewhat
advanced topic if you're new to programming and OO...).
 
J

James Stroud

Fulvio said:
***********************
Your mail has been scanned by InterScan MSS.
***********************




I'm in that matter too. Doesn't classes make the main program neater?
Fundamentally OOP is the way to assemble ready objects to get a "thing"
working, rather than worry about any single code line.
Is this a concept of python?

I don't really have formal programming training, but it is increasingly
becoming my experience that OOP is but one ingredient in a good program.
It can be left out or it can be mixed with other ingredients for a nice
effect. Take for example the "file" and "open" built-ins. Calling both
creates a file object, but the latter, which is the preferred to open a
file, is actually a function rather than a class. So even the python
designers did not constrain themselves to any single "style".

I think the trick is to identify when a class would make more sense than
a collection of subroutines, etc.

James
 
S

Simon Brunning

I don't really have formal programming training, but it is increasingly
becoming my experience that OOP is but one ingredient in a good program.
It can be left out or it can be mixed with other ingredients for a nice
effect.

Indeed. Python is a multi-paradigm programing language. If the best
solution for a problem is a class, you've got them. If on the other
hand, you just need a function, you can have one of those too - none
of this class full of static methods rubbish like you have in Java. If
a functional approach is better, Python does that.
 
F

Fulvio

***********************
Your mail has been scanned by InterScan MSS.
***********************


I think the trick is to identify when a class would make more sense than
a collection of subroutines

I do believe that's a bit of forecasting, in sense to determine whether a
piece of code may have a future. Usually in hobbistic term I think we can
bear with copy&pasting pieces of code across programs rather than go for a
class(es) module.
Only I remembered the mottos when I ran this,py which gives me some good
points of view.

F
 
B

bruno de chez modulix en face

Fulvio a écrit :
***********************
Your mail has been scanned by InterScan MSS.
***********************




I do believe that's a bit of forecasting, in sense to determine whether a
piece of code may have a future.
Usually in hobbistic term I think we can
bear with copy&pasting pieces of code across programs rather than go for a
class(es) module.

OO and reuse are two orthogonal concerns. You don't need OO to reuse
code, and OO is not so much about code reuse - even if it can improve
reusability - than about how to best structure your code.

To illustrate James' POV, if you end up with half a dozen functions
working on a same well-defined data structure, then it might be time
to 'integrate' these functions and the data structure into a class.
Some other hints are when you have a small set of functions depending
on a common set of globals, or when you find yourself adding to your
functions signature too much additional params that are only meant to
be passed to other functions that themselves will pass them etc...

Copy-paste reuse should IMHO be limited to very trivial helper
functions that are not worth the pain of dependencies management...

My 2 cents
 

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

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top