9.7. Odds and Ends Sometimes it is useful to have a data type similar to the Pascal “record” or C “struct”, bundling together a few named data items. An empty class definition will do nicely: A piece of Python code that expects a particular abstract data type can often be passed a class that emulates the methods of that data type instead. For instance, if you have a function that formats some data from a file object, you can define a class with methods read() and that get the data from a string buffer instead, and pass it as an argument. Instance method objects have attributes, too: m.im_self is the instance object with the method m(), and m.im_func is the function object corresponding to the method. 9.8. Exceptions Are Classes Too User-defined exceptions are identified by classes as well. Using this mechanism it is possible to create extensible hierarchies of exceptions. There are two new valid (semantic) forms for the statement: In the first form, instance must be an instance of Class or of a class derived from it. The second form is a shorthand for: A class in an clause is compatible with an exception if it is the same class or a base class thereof (but not the other way around — an except clause listing a derived class is not compatible with a base class). For example, the following code will print B, C, D in that order: Note that if the except clauses were reversed (with except B first), it would have printed B, B, B — the first matching except clause is triggered. When an error message is printed for an unhandled exception, the exception’s class name is printed, then a colon and a space, and finally the instance converted to a string using the built-in function . 9.9. Iterators By now you have probably noticed that most container objects can be looped over using a statement: This style of access is clear, concise, and convenient. The use of iterators pervades and unifies Python. Behind the scenes, the statement calls on the container object. The function returns an iterator object that defines the method which accesses elements in the container one at a time. When there are no more elements, raises a exception which tells the loop to terminate. This example shows how it all works: File Having seen the mechanics behind the iterator protocol, it is easy to add iterator behavior to your classes. Define an method which returns an object with a method. If the class defines , then can just return self: 9.10. Generators s are a simple and powerful tool for creating iterators. They are written like regular functions but use the statement whenever they want to return data. Each time is called, the generator resumes where it left-off (it remembers all the data values and which statement was last executed). An example shows that generators can be trivially easy to create: Anything that can be done with generators can also be done with class based iterators as described in the previous section. What makes generators so compact is that the and methods are created automatically. Another key feature is that the local variables and execution state are automatically saved between calls. This made the function easier to write and much more clear than an approach using instance variables like self.index and self.data. In addition to automatic method creation and saving program state, when generators terminate, they automatically raise . In combination, these features make it easy to create iterators with no more effort than writing a regular function. 9.11. Generator Expressions Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of brackets. These expressions are designed for situations where the generator is used right away by an enclosing function. Generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions. Examples: Footnotes Except for one thing. Module objects have a secret read-only attribute called __dict__ which returns the dictionary used to implement the module’s namespace; the name __dict__ is an attribute but not a global name. Obviously, using this violates the abstraction of namespace implementation, and should be restricted to things like post-mortem debuggers. (责任编辑:JavaVideo) |
