Chapter 5. Objects and Object-Orientation
This chapter, and pretty much every chapter after this, deals with object-
oriented Python programming.
5.1. Diving In
Here is a complete, working Python program. Read the doc strings of
the module, the classes, and the functions to get an overview of what this
program does and how it works. As usual, don't worry about the stuff you
don't understand; that's what the rest of the chapter is for.
Example 5.1. fileinfo.py
If you have not already done so, you can download this and other examples
used in this book.
"""Framework for getting filetype-specific
metadata.
Instantiate appropriate class with filename.
Returned object acts like a
dictionary, with key-value pairs for each piece of
metadata.
import fileinfo
info =
fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
print "\\n".join(["%s=%s" % (k, v) for k, v in
info.items()])
Or use listDirectory function to get info on all
files in a directory.
for info in
fileinfo.listDirectory("/music/ap/", [".mp3"]):
...
Framework can be extended by adding classes for
"comment" : ( 97, 126,
stripnulls),
"genre" : (127, 128, ord)}
def __parse(self, filename):
"parse ID3v1.0 tags from MP3 file"
self.clear()
try:
fsock = open(filename, "rb", 0)
try:
fsock.seek(-128, 2)
tagdata = fsock.read(128)
finally:
fsock.close()
if tagdata[:3] == "TAG":
for tag, (start, end, parseFunc) in
self.tagDataMap.items():
self[tag] =
parseFunc(tagdata[start:end])
except IOError:
pass
def __setitem__(self, key, item):
if key == "name" and item:
self.__parse(item)
FileInfo.__setitem__(self, key, item)
def listDirectory(directory, fileExtList):
"get list of file info objects for files of
particular extensions"
artist=Ghost in the Machine
title=A Time Long Forgotten (Concept
genre=31
name=/music/_singles/a_time_long_forgotten_con.mp3
year=1999
comment=
album=Rave Mix
artist=***DJ MARY-JANE***
title=HELLRAISER****Trance from Hell
genre=31
name=/music/_singles/hellraiser.mp3
year=2000
comment=
album=Rave Mix
artist=***DJ MARY-JANE***
title=KAIRO****THE BEST GOA
genre=31
name=/music/_singles/kairo.mp3
year=2000
comment=
album=Journeys
artist=Masters of Balance
title=Long Way Home
genre=31
name=/music/_singles/long_way_home1.mp3
year=2000
comment=
import module in Python is like require module in Perl.
from module import * in Python is like import module.* in
Java; import module in Python is like import module in Java.
Example 5.2. import module vs. from module import
>>> import types
>>> types.FunctionType
<type 'function'>
>>> FunctionType
Traceback (innermost last):
File "<interactive input>", line 1, in ?
NameError: There is no variable named
'FunctionType'
>>> from types import FunctionType
>>> FunctionType
<type 'function'>
The types module contains no methods; it just has attributes for each
Python object type. Note that the attribute, FunctionType, must be
qualified by the module name, types.
FunctionType by itself has not been defined in this namespace; it
exists only in the context of types.
This syntax imports the attribute FunctionType from the types
module directly into the local namespace.
Now FunctionType can be accessed directly, without reference to
types.
When should you use from module import?
The name of this class is Loaf, and it doesn't inherit from any other class.
Class names are usually capitalized, EachWordLikeThis, but this is
only a convention, not a requirement.
This class doesn't define any methods or attributes, but syntactically, there
needs to be something in the definition, so you use pass. This is a Python
reserved word that just means “move along, nothing to see here”. It's a
statement that does nothing, and it's a good placeholder when you're
stubbing out functions or classes.
You probably guessed this, but everything in a class is indented, just like
the code within a function, if statement, for loop, and so forth. The first
thing not indented is not in the class.
The pass statement in Python is like an empty set of braces ({}) in
Java or C.
Of course, realistically, most classes will be inherited from other classes, and
they will define their own class methods and attributes. But as you've just
seen, there is nothing that a class absolutely must have, other than a name. In
particular, C++ programmers may find it odd that Python classes don't have
explicit constructors and destructors. Python classes do have something
similar to a constructor: the __init__ method.
Example 5.4. Defining the FileInfo Class
from UserDict import UserDict
class FileInfo(UserDict):
In Python, the ancestor of a class is simply listed in parentheses
immediately after the class name. So the FileInfo class is inherited
from the UserDict class (which was imported from the UserDict
nature). Incorrect, because the object has already been constructed by the
time __init__ is called, and you already have a valid reference to the
new instance of the class. But __init__ is the closest thing you're
going to get to a constructor in Python, and it fills much the same role.
The first argument of every class method, including __init__, is
always a reference to the current instance of the class. By convention, this
argument is always named self. In the __init__ method, self
refers to the newly created object; in other class methods, it refers to the
instance whose method was called. Although you need to specify self
explicitly when defining the method, you do not specify it when calling
the method; Python will add it for you automatically.
__init__ methods can take any number of arguments, and just like
functions, the arguments can be defined with default values, making them
optional to the caller. In this case, filename has a default value of
None, which is the Python null value.
By convention, the first argument of any Python class method (the
reference to the current instance) is called self. This argument fills the
role of the reserved word this in C++ or Java, but self is not a
reserved word in Python, merely a naming convention. Nonetheless,
please don't call it anything but self; this is a very strong convention.
Example 5.6. Coding the FileInfo Class
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
to extend the behavior of the ancestor, the descendant method must
explicitly call the ancestor method at the proper time, with the proper
arguments.
Further Reading on Python Classes
Learning to Program has a gentler introduction to classes.
How to Think Like a Computer Scientist shows how to use classes to
model compound datatypes.
Python Tutorial has an in-depth look at classes, namespaces, and
inheritance.
Python Knowledge Base answers common questions about classes.
5.4. Instantiating Classes
Instantiating classes in Python is straightforward. To instantiate a class,
simply call the class as if it were a function, passing the arguments that the
__init__ method defines. The return value will be the newly created
object.
Example 5.7. Creating a FileInfo Instance
>>> import fileinfo
>>> f =
fileinfo.FileInfo("/music/_singles/kairo.mp3")