预计阅读本页时间:-
Example
As we’ve seen, classes are mostly just namespaces—that is, tools for defining names (i.e., attributes) that export data and logic to clients. So, how do you get from the class statement to a namespace?
Here’s how. Just like in a module file, 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:
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
- Like functions, class statements are local scopes where names created by nested assignments live.
- Like names in a module, 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; reference attributes that are not found in a class or instance object are fetched from other classes.
Because class is a compound statement, any sort of statement can be nested inside its body—print, =, if, def, and so on. All the statements inside the class statement run when the class statement itself runs (not when the class is later called to make an instance). Assigning names inside the class statement makes class attributes, and nested defs make class methods, but other assignments make attributes, too.
For example, assignments of simple nonfunction objects to class attributes produce data attributes, shared by all instances:
>>> class SharedData:
... spam = 42 # Generates a class data attribute
...
>>> x = SharedData() # Make two instances
>>> y = SharedData()
>>> x.spam, y.spam # They inherit and share 'spam'
(42, 42)
Here, because the name spam is assigned at the top level of a class statement, it is attached to the class and so will be shared by all instances. We can change it by going through the class name, and we can refer to it through either instances or the class.[63]
>>> SharedData.spam = 99
>>> x.spam, y.spam, SharedData.spam
(99, 99, 99)
Such class attributes can be used to manage information that spans all the instances—a counter of the number of instances generated, for example (we’ll expand on this idea by example in Chapter 31). Now, watch what happens if we assign the name spam through an instance instead of the class:
>>> x.spam = 88
>>> x.spam, y.spam, SharedData.spam
(88, 99, 99)
Assignments to instance attributes create or change the names in the instance, rather than in the shared class. More generally, inheritance searches occur only on attribute references, not on assignment: assigning to an object’s attribute always changes that object, and no other.[64] For example, y.spam is looked up in the class by inheritance, but the assignment to x.spam attaches a name to x itself.
Here’s a more comprehensive example of this behavior that stores the same name in two places. Suppose we run the following class:
class MixedNames: # Define class
data = 'spam' # Assign class attr
def __init__(self, value): # Assign method name
self.data = value # Assign instance attr
def display(self):
print(self.data, MixedNames.data) # Instance attr, class attr
This class contains two defs, which bind class attributes to method functions. It also contains an = assignment statement; because this assignment assigns the name data inside the class, it lives in the class’s local scope and becomes an attribute of the class object. Like all class attributes, this data is inherited and shared by all instances of the class that don’t have data attributes of their own.
When we make instances of this class, the name data is attached to those instances by the assignment to self.data in the constructor method:
>>> x = MixedNames(1) # Make two instance objects
>>> y = MixedNames(2) # Each has its own data
>>> x.display(); y.display() # self.data differs, MixedNames.data is the same
1 spam
2 spam
The net result is that data lives in two places: in the instance objects (created by the self.data assignment in __init__), and in the class from which they inherit names (created by the data assignment in the class). The class’s display method prints both versions, by first qualifying the self instance, and then the class.
By using these techniques to store attributes in different objects, we determine their scope of visibility. When attached to classes, names are shared; in instances, names record per-instance data, not shared behavior or data. Although inheritance searches look up names for us, we can always get to an attribute anywhere in a tree by accessing the desired object directly.
In the preceding example, for instance, specifying x.data or self.data will return an instance name, which normally hides the same name in the class; however, MixedNames.data grabs the class name explicitly. We’ll see various roles for such coding patterns later; the next section describes one of the most common.
[63] If you’ve used C++ you may recognize this as similar to the notion of C++’s “static” data members—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”). In Chapter 31, we’ll also meet Python static methods (akin to those in C++), which are just self-less functions that usually process class attributes.
[64] Unless the class has redefined the attribute assignment operation to do something unique with the __setattr__ operator overloading method (discussed in Chapter 29).