预计阅读本页时间:-
Implementation Details 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
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
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.