首页 > 代码库 > <Python> Classes
<Python> Classes
Classes
Python classes provide all the standard features of Object Oriented Programming: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class or classes, and a method can call the method of a base class with the same name.
The simplest form of class definition looks like this:
class ClassName: <statement-1> . . . <statement-N>
Class definitions, like function definitions (def
statements) must be executed before they have any effect. (You could conceivably place a class definition in a branch of an if
statement, or inside a function.)
When a class definition is entered, a new namespace is created, and used as the local scope — thus, all assignments to local variables go into this new namespace. In particular, function definitions bind the name of the new function here.
Random Remarks
Data attributes override method attributes with the same name; to avoid accidental name conflicts, which may cause hard-to-find bugs in large programs, it is wise to use some kind of convention that minimizes the chance of conflicts. Possible conventions include capitalizing method names, prefixing data attribute names with a small unique string (perhaps just an underscore), or using verbs for methods and nouns for data attributes.
Clients should use data attributes with care — clients may mess up invariants maintained by the methods by stamping on their data attributes. Note that clients may add data attributes of their own to an instance object without affecting the validity of the methods, as long as name conflicts are avoided — again, a naming convention can save a lot of headaches here.
There is no shorthand for referencing data attributes (or other methods!) from within methods. I find that this actually increases the readability of methods: there is no chance of confusing local variables and instance variables when glancing through a method. Use "self.instanceVariables".
Often, the first argument of a method is called self
. This is nothing more than a convention: the name self
has absolutely no special meaning to Python. Note, however, that by not following the convention your code may be less readable to other Python programmers, and it is also conceivable that a class browser program might be written that relies upon such a convention.
Inheritance
The syntax for a derived class definition looks like this:
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
The name BaseClassName
must be defined in a scope containing the derived class definition. In place of a base class name, other arbitrary expressions are also allowed. This can be useful, for example, when the base class is defined in another module:
class DerivedClassName(modname.BaseClassName):
Multiple Inheritance
Python supports a limited form of multiple inheritance as well. A class definition with multiple base classes looks like this:
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
For old-style classes, the only rule is depth-first, left-to-right. Thus, if an attribute is not found in DerivedClassName
, it is searched in Base1
, then (recursively) in the base classes of Base1
, and only if it is not found there, it is searched in Base2
, and so on.
For new-style classes, the method resolution order changes dynamically to support cooperative calls to super()
. This approach is known in some other multiple-inheritance languages as call-next-method and is more powerful than the super call found in single-inheritance languages.
With new-style classes, dynamic ordering is necessary because all cases of multiple inheritance exhibit one or more diamond relationships (where at least one of the parent classes can be accessed through multiple paths from the bottommost class). For example, all new-style classes inherit from object
, so any case of multiple inheritance provides more than one path to reach object
. To keep the base classes from being accessed more than once, the dynamic algorithm linearizes the search order in a way that preserves the left-to-right ordering specified in each class, that calls each parent only once, and that is monotonic (meaning that a class can be subclassed without affecting the precedence order of its parents). Taken together, these properties make it possible to design reliable and extensible classes with multiple inheritance. For more detail, see https://www.python.org/download/releases/2.3/mro/.
Private Variables and Class-local Reference
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam
) should be treated as a non-public part of the API (whether it is a function, a method or a data member).
Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam
(at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam
, where classname
is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls. For example:
class Mapping: def __init__(self, iterable): self.items_list = [] self.__update(iterable) def update(self, iterable): for item in iterable: self.items_list.append(item) __update = update # private copy of original update() methodclass MappingSubclass(Mapping): def update(self, keys, values): # provides new signature for update() # but does not break __init__() for item in zip(keys, values): self.items_list.append(item)
Note that the mangling rules are designed mostly to avoid accidents; it still is possible to access or modify a variable that is considered private. This can even be useful in special circumstances, such as in the debugger.
Iterators
By now you have probably noticed that most container objects can be looped over using a for
statement:
for element in [1, 2, 3]: print elementfor element in (1, 2, 3): print elementfor key in {‘one‘:1, ‘two‘:2}: print keyfor char in "123": print charfor line in open("myfile.txt"): print line,
This style of access is clear, concise, and convenient. The use of iterators pervades and unifies Python. Behind the scenes, the for
statement calls iter()
on the container object. The function returns an iterator object that defines the method next()
which accesses elements in the container one at a time.
Having seen the mechanics behind the iterator protocol, it is easy to add iterator behavior to your classes. Define an__iter__()
method which returns an object with a next()
method. If the class defines next()
, then __iter__()
can just return self
:
class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def next(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index]
>>> rev = Reverse(‘spam‘)>>> iter(rev)<__main__.Reverse object at 0x00A1DB50>>>> for char in rev:... print char...maps
<Python> Classes