|
Python for experienced programmers |
|
3.6. Defining classes
Python is fully object-oriented: you can define your own classes, inherit from your own or built-in classes, and instantiate the classes you've defined.
Defining a class in Python is simple; like functions, there is no separate interface definition. Just define the class and start coding. A Python class starts with the reserved word class, followed by the class name. Technically, that's all that's required, since a class doesn't have to inherit from any other class.
Example 3.12. The simplest Python class
class foo:
pass

| The name of this class is foo, and it doesn't inherit from any other class. |
| This class doesn't define any methods or attributes, but syntactically, there needs to be something in the definition, so we use pass. This is a Python reserved word that just means “move along, nothing to see here”. It is the equivalent of an empty set of braces in C++ or a single semi-colon in Java. 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. |
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 3.13. Defining the FileInfo class
from UserDict import UserDict
class FileInfo(UserDict):
"base class for file info"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename

| The ancestors of a class are listed in parentheses immediately after the class name. So the FileInfo class is inherited from the UserDict class (which was imported from the UserDict module). UserDict is a class that acts like a dictionary, allowing you to essentially subclass the dictionary datatype and add your own behavior. (There are similar classes UserList and UserString which allow you to subclass lists and strings.) There is a bit of black magic behind this, which we will demystify later in this chapter when we explore the UserDict class in more depth. |
| Classes can have doc strings too, just like modules and functions. |
| __init__ is called immediately after an instance of the class is created. It would be tempting but incorrect to call this the constructor of the class. Tempting, because it looks like a constructor (by convention, __init__ is the first method defined for the class), acts like one (it's the first piece of code executed in a newly created instance of the class), and even sounds like one (“init” certainly suggests a constructor-ish 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. |
| 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 named self. (Please don't call it anything but self; this is a very strong convention.) self is like the reserved word this in C++. In the __init__ method, self refers to the newly created object; in other class methods, it refers to the object whose method was called. |
| __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, name has a default value of None, which is the Python null value. |
| Some pseudo-object-oriented languages like Powerbuilder have a concept of “extending” constructors and other events, where the ancestor's method is called automatically before the descendant's method is executed. Python does not do this; you must always explicitly call the appropriate method in the ancestor class. Also, when calling ancestor class methods, you must include the self argument, along with any other arguments the class method takes. In this case, we're calling the __init__ method of the UserDict class with no arguments (other than self). |
| I told you that this class acts like a dictionary, and here is the first sign of it. We're assigning the argument filename as the value of this object's name key. |
| Note that the __init__ method never returns a value. |
Whew. I realize that's a lot to absorb, but you'll get the hang of it. All Python classes work the same way, so once you learn one, you've learned them all. Plus, there are very strong conventions in the Python community for things like naming the first parameter of each class method “self”, so you won't waste a lot of time getting used to other people's style. If you forget everything else, remember this one thing, because I promise it will trip you up:
 |
__init__ methods are optional, but when you define one, you must remember to explicitly call the ancestor's __init__ method. This is more generally true: whenever a descendant wants to extend the behavior of the ancestor, the descendant method must explicitly call the ancestor method at the proper time, with the proper arguments. |