Read Programming Python Online

Authors: Mark Lutz

Tags: #COMPUTERS / Programming Languages / Python

Programming Python (178 page)

BOOK: Programming Python
4.77Mb size Format: txt, pdf, ePub
ads
SQL Resources

Although the
examples we’ve seen in this section are simple, their
techniques scale up to much more realistic databases and contexts. The
websites we studied in the prior part of the book, for instance, can
make use of SQL-based systems such as MySQL to store page state
information as well as long-lived client information. Because MySQL
(among others) supports both large databases and concurrent updates,
it’s a natural for website implementation.

There is more to database interfaces than we’ve seen, but
additional API documentation is readily available on the Web. To find
the full database API specification, search the Web for “Python Database
API.” You’ll find the formal API definition—really just a text file
describing the PEP (the Python Enhancement Proposal) under which the API
was hashed out.

Perhaps the best resource for additional information about
database extensions today is the home page of the Python database SIG.
Go to
http://www.python.org
, click on the
Community and SIGs links there, and navigate to the database group’s
page, or run a search. There, you’ll find API documentation (this is
where it is officially maintained), links to database vendor–specific
extension modules, and more. And as always, see the PyPI website and
search the Web at large for related third-party tools and
extensions.

ORMs: Object Relational Mappers

In this chapter,
we’ve seen OODBs that store native Python objects
persistently, as well as SQL databases that store information in tables.
It turns out that there is another class of system that attempts to bridge
the object and table worlds, which I’ve hinted at earlier in this chapter:
ORMs graft the Python class model onto the tables of relational databases.
They combine the power of relational database systems with the simplicity
of Python class-based syntax—you don’t need to forgo SQL-based
databases
, but you can still store data that
seems like Python objects to your scripts.

Today, there are two leading open source third-party systems that
implement this mapping: SQLObject and SQLAlchemy. Both are fairly complex
systems that we cannot do full justice to in this text, and you’re best
off researching their documentation on the Web for the full story (there
are also dedicated books covering SQLAlchemy today). Moreover, neither is
completely Python 3.X ready as I write these words, so we can’t run live
examples with them in this text.

To give you a slightly more concrete flavor of the ORM model,
though, here is a very quick look at how you might use it to create and
process database records in the
SQLObject
system. In brief, SQLObject maps:

  • Python classes to database tables

  • Python class instances to rows in the table

  • Python instance attributes to row columns

For example, to create a table, we define it with a class, with
class attributes that define columns, and call its creation method (this
code is derived from a more complete example at SQLObject’s
website):

from sqlobject import *
sqlhub.processConnection = connectionForURI('sqlite:/:memory:')
class Person(SQLObject): # class: describes table
first = StringCol() # class attributes: row columns
mid = StringCol(length=1, default=None)
last = StringCol()
Person.createTable() # create a database table

Once created, making an instance automatically inserts a row into
the database, and attribute fetches and assignments are automatically
mapped to fetches and updates of the corresponding table row’s
column:

p = Person(first='Bob', last='Smith')     # new instance: makes and inserts row
p # prints all attributes by name
p.first # attribute: fetches row column
p.mid = 'M' # attribute: updates record

Existing rows/instances may be fetched by methods calls, and we can
assign multiple columns/attributes with a single update operation:

p2 = Person.get(1)                        # fetch existing record/instance: p2 is p
p.set(first='Tom', last='Jones') # update two attributes/fields at once

In addition, we can select by column values by creating a query
object and executing it:

ts = Person.select(Person.q.first=='Tom') # query: select by column value
list(ts) # run the query: list of instances
tjs = Person.selectBy(first='Tom', last='Jones') # alternative query form (AND)

Naturally, this barely scratches the surface of the available
functionality. Even at this level of complexity, though, this is quite a
trick—SQLObject automatically issues all the SQL required to fetch, store,
and query the table and rows implied by the Python class syntax here.
Again, the net effect allows systems to leverage the power of
enterprise
-
level
relational databases, but still use
familiar Python class syntax to process stored data in Python
scripts.

The code used with the SQLAlchemy ORM is of course very different,
but the end result is functionally similar. For more details on ORMs for
Python, consult your friendly neighborhood web search engine. You can also
learn more about such systems by their roles in some larger web
development frameworks; Django, for instance, has an ORM which is another
variation on this
theme.

PyForm: A Persistent Object Viewer (External)

Instead of going into
additional database interface details that are freely
available on the Web, I’m going to close out this chapter by directing you
to a supplemental example that shows one way to combine the GUI technology
we met earlier in the text with the persistence techniques introduced in
this chapter. This example is named PyForm—a Python/tkinter GUI designed
to let you browse and edit tables of records:

  • Tables browsed may be shelves, DBM files, in-memory
    dictionaries, or any other object that looks and feels like a
    dictionary.

  • Records within tables browsed can be class instances, simple
    dictionaries, strings, or any other object that can be translated to
    and from a dictionary.

Although this example is about GUIs and persistence, it also
illustrates Python design techniques. To keep its implementation both
simple and type-independent, the PyForm GUI is coded to expect tables to
look like dictionaries of dictionaries. To support a variety of table and
record types, PyForm relies on separate wrapper classes to translate
tables and records to the expected protocol:

  • At the top table level, the translation is easy—shelves, DBM
    files, and in-memory dictionaries all have the same key-based
    interface.

  • At the nested record level, the GUI is coded to assume that
    stored items have a dictionary-like interface, too, but classes
    intercept dictionary operations to make records compatible with the
    PyForm protocol. Records stored as strings are converted to and from
    the dictionary objects on fetches and stores; records stored as class
    instances are translated to and from attribute dictionaries. More
    specialized translations can be added in new table wrapper
    classes.

The net effect is that PyForm can be used to browse and edit a wide
variety of table types, despite its dictionary interface expectations.
When PyForm browses shelves and DBM files, table changes made within the
GUI are persistent—they are saved in the underlying files. When used to
browse a shelve of class instances, PyForm essentially becomes a GUI
frontend to a simple object database that is built using standard Python
persistence tools. To view and update a shelve of objects with PyForm, for
example, code like the following will suffice:

import shelve
from formgui import FormGui # after initcast
db = shelve.open('../data/castfile') # reopen shelve file
FormGui(db).mainloop() # browse existing shelve-of-dicts

To view or update a shelve of instances of an imported
Actor
class, we can use code like this:

from PP4E.Dbase.testdata inport Actor
from formgui import FormGui # run in TableBrowser dir
from formtable import ShelveOfInstance
testfile = '../data/shelve' # external filename
table = ShelveOfInstance(testfile, Actor) # wrap shelf in Table object
FormGui(table).mainloop()
table.close() # close needed for some dbm

Figure 17-1
captures
the scene under Python 3.1 and Windows 7 when viewing a shelve of
persistent class instance objects. This PyForm session was kicked off by a
command-line described in its form table module’s self-test code:
formtable.py shelve 1
, and omit the
1
(or pass it as
0
) to avoid reinitializing the shelve at the
start of each session so changes are retained.

PyForm’s GUI can also be started from the PyDemos launcher we met in
Chapter 10
, though it does not save changes
persistently in this mode. Run the example on your own computer to get a
better sample of its operation. Though not a fully general Python
persistent object table viewer, PyForm serves as a simple object database
front end.

Figure 17-1. PyForm displaying a shelve of Actor objects

Because we are short on time and space in this edition, I’m going to
omit both the source code for this example and its description here. To
study PyForm, see the following directory in the book’s examples package
distribution described in the
Preface
:

C:\...\PP4E\Dbase\TableBrowser

See especially the
Documentation
subdirectory there, which
contains the original
PyForm
overview material from the third edition in a PDF file. PyForm’s source
code files are ported to Python 3.X form, though code in the overview
document still shows its 2.X third edition roots. For the purposes of the
published portions of this book, let’s move on to the next chapter and our
next tools topic: data structure
implementations.

Chapter 18. Data Structures
“Roses Are Red, Violets Are Blue; Lists Are Mutable,
and So Is Set Foo”

Data structures are a central theme in most programs, even if Python
programmers often don’t need to care. Their apathy is warranted—Python
comes “out of the box” with a rich set of built-in and already optimized
types that make it easy to deal with structured data: lists, strings,
tuples, dictionaries, sets, and the like. For simple systems, these types
are usually enough. Dictionaries, for example, subsume many of the
classical searching algorithms, and lists replace much of the work you’d
do to support collections in lower-level languages. Even so, both are so
easy to use that you generally never give them a second thought.

But for advanced applications, we may need to add more sophisticated
types of our own to handle extra requirements or special cases. In this
chapter, we’ll explore a handful of advanced data structure
implementations in Python: sets, stacks, graphs, and so on. As we’ll see,
data structures can take the form of new object types in Python,
integrated into the language’s type model. That is, objects we code in
Python become full-fledged
datatypes
—to the scripts
that use them, they can look and feel just like built-in lists, numbers,
and dictionaries.

Although the examples in this chapter illustrate advanced
programming and computer science techniques, they also underscore Python’s
support for writing
reusable
software. As object
implementations are coded with classes and modules, they naturally become
generally useful components that can be used in any program that imports
them. In effect, we will be building
libraries
of
data structure tools, whether we plan for it or not.

Moreover, though most examples in this chapter are pure Python code
(and at least to linear readers, some may seem relatively simple compared
to those of earlier chapters), they also provide a use case for discussing
Python performance issues, and hint at what’s possible with the subject of
Chapter 20
—from the most general
perspective, new
Python
objects can
be implemented in either Python or an integrated language such as C. Types
coded in C use patterns similar to those here.

In the end, though, we’ll also see that Python’s built-in support
can often take the place of homegrown solutions in this domain. Although
custom data structure implementations are sometimes necessary and still
have much to offer in terms of code maintenance and evolution, they are
not always as paramount in Python as they are in less programmer-friendly
languages.

BOOK: Programming Python
4.77Mb size Format: txt, pdf, ePub
ads

Other books

Sparkle by Rudy Yuly
Thorn Jack by Katherine Harbour
The Virtuous Assassin by Anne, Charlotte
What She Needs by Anne Calhoun
The Extra Yard by Mike Lupica
We Shall Rise by J.E. Hopkins
Writ in Stone by Cora Harrison