Online Book Reader

Home Category

Learning Python - Mark Lutz [550]

By Root 1769 0
II

To help you analyze the code, here are a few final notes on this version. Since this is just a generalization of the preceding section’s example, most of the notes there apply here as well.

Using __X pseudoprivate names

Besides generalizing, this version also makes use of Python’s __X pseudoprivate name mangling feature (which we met in Chapter 30) to localize the wrapped attribute to the control class, by automatically prefixing it with the class name. This avoids the prior version’s risk for collisions with a wrapped attribute that may be used by the real, wrapped class, and it’s useful in a general tool like this. It’s not quite “privacy,” though, because the mangled name can be used freely outside the class. Notice that we also have to use the fully expanded name string ('_onInstance__wrapped') in __setattr__, because that’s what Python changes it to.

Breaking privacy

Although this example does implement access controls for attributes of an instance and its classes, it is possible to subvert these controls in various ways—for instance, by going through the expanded version of the wrapped attribute explicitly (bob.pay might not work, but the fully mangled bob._onInstance__wrapped.pay could!). If you have to explicitly try to do so, though, these controls are probably sufficient for normal intended use. Of course, privacy controls can generally be subverted in any language if you try hard enough (#define private public may work in some C++ implementations, too). Although access controls can reduce accidental changes, much of this is up to programmers in any language; whenever source code may be changed, access control will always be a bit of a pipe dream.

Decorator tradeoffs

We could again achieve the same results without decorators, by using manager functions or coding the name rebinding of decorators manually; the decorator syntax, however, makes this consistent and a bit more obvious in the code. The chief potential downsides of this and any other wrapper-based approach are that attribute access incurs an extra call, and instances of decorated classes are not really instances of the original decorated class—if you test their type with X.__class__ or isinstance(X, C), for example, you’ll find that they are instances of the wrapper class. Unless you plan to do introspection on objects’ types, though, the type issue is probably irrelevant.

Open Issues

As is, this example works as planned under Python 2.6 and 3.0 (provided operator overloading methods to be delegated are redefined in the wrapper). As with most software, though, there is always room for improvement.

Caveat: operator overloading methods fail to delegate under 3.0

Like all delegation-based classes that use __getattr__, this decorator works cross-version for normally named attributes only; operator overloading methods like __str__ and __add__ work differently for new-style classes and so fail to reach the embedded object if defined there when this runs under 3.0.

As we learned in the prior chapter, classic classes look up operator overloading names in instances at runtime normally, but new-style classes do not—they skip the instance entirely and look up such methods in classes. Hence, the __X__ operator overloading methods implicitly run for built-in operations do not trigger either __getattr__ or __getattribute__ in new-style classes in 2.6 and all classes in 3.0; such attribute fetches skip our onInstance.__getattr__ altogether, so they cannot be validated or delegated.

Our decorator’s class is not coded as new-style (by deriving from object), so it will catch operator overloading methods if run under 2.6. Since all classes are new-style automatically in 3.0, though, such methods will fail if they are coded on the embedded object. The simplest workaround in 3.0 is to redefine redundantly in onInstance all the operator overloading methods that can possibly be used in wrapped objects. Such extra methods can be added by hand, by tools that partly automate the task (e.g., with class decorators or the

Return Main Page Previous Page Next Page

®Online Book Reader