Did all of the above make sense? If not, don’t worry; now that
we’ve had a quick tour, we’re going to dig a bit deeper
and study the concepts we’ve introduced in more detail. We met
the class
statement in our first examples, but let’s formalize some of
the ideas we introduced. As in C++, the class
statement is Python’s main OOP tool. Unlike in C++,
class
isn’t really a declaration; like
def
, class
is an object
builder, and an implicit assignment—when run, it generates a
class object, and stores a reference to it in the name used in the
header.
As we saw on our quick tour, class
is a compound
statement with a body of indented statements under it. In the header,
superclasses are listed in parentheses after the class name,
separated by commas. Listing more than one superclass leads to
multiple inheritance (which we’ll say more about later in this
chapter):
class <name>(superclass,...): # assign to name data = value # shared class data def method(self,...): # methods self.member = value # per-instance data
Within the class statement, specially-named methods overload
operators; for instance, a function called
_
_ init
__
is called at
instance object construction time, if defined.
At the start of this chapter, we mentioned that classes are mostly just namespaces— a tool for defining names (called attributes) that export data and logic to clients. So how do you get from the statement to a namespace?
Here’s how. Just as with modules, the statements nested in a
class
statement body create its attributes. When
Python executes a class
statement (not a call to a
class), it runs all the statements in its body from top to bottom.
Assignments that happen during this process create names in the
class’s local scope, which become attributes in the associated
class object. Because of this, classes resemble both modules and
functions:
Like functions, class
statements are a local scope
where names created by nested assignments live.
Like modules, names assigned in a class
statement
become attributes in a class object.
The main distinction for classes is that their namespaces are also
the basis of inheritance in Python; attributes are fetched from other
classes if not found in a class or instance object. Because
class
is a compound statement, any sort of
statement can be nested inside its body—for instance,
print
, =
,
if
, and def
. As we’ve
seen, nested defs
make class methods, but other
assignments make attributes too. For example, suppose we run the
following class:
class Subclass(aSuperclass): # define subclass data = 'spam' # assign class attr def __init__(self, value): # assign class attr self.data = value # assign instance attr def display(self): print self.data, Subclass.data # instance, class
This class contains two defs
, which bind class
attributes to method functions. It also contains a
=
assignment statement; since the name
data
is assigned inside the
class
, it lives in the class’s local scope
and becomes an attribute of the class object. Like all class
attributes, data
is inherited and
shared by all instances of the class:[45]
>>>x = Subclass(1)
# make two instance objects >>>y = Subclass(2)
# each has its own "data" >>>x.display(); y.display()
# "self.data" differs, "Subclass.data" same 1 spam 2 spam
When we run this code, the name data
lives in two
places—in instance objects (created in the
__ init
__
constructor)
and in the
class they inherit names from (created by the =
assignment). The class’s display
method
prints both versions, by first qualifying the self instance, and then
the class itself. Since classes are objects with attributes, we can
get to their names by qualifying, even if there’s no instance
involved.
[45] If you’ve used C++, you may recognize this as similar to
the notion of C++’s static
class
data—members that are stored in the class, independent of
instances. In Python, it’s nothing special: all class
attributes are just names assigned in the class
statement, whether they happen to reference functions (C++’s
methods) or something else (C++’s
members).