文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- 61.182.251.106 [2004-11-21 02:13:53]

1. 描述

Delegating Automatically as an Alternative to Inheritance

使用自动代理,代替继承

Credit: Alex Martelli

1.1. 问题 Problem

You'd like to inherit from a built-in type, but you are using Python 2.1 (or earlier), or need a semantic detail of classic classes that would be lost by inheriting from a built-in type in Python 2.2. 希望继承内置类型,但是正在使用Python2.1及更早版本, 换句话说,继承python2.2中的内置类型会导致信息丢失?, 需要语义处理

1.2. 解决 Solution

With Python 2.2, we can inherit directly from a built-in type. For example, we can subclass file with our own new-style class and override some methods:

python 2.2中,可以从内置类型继承,比如,可以继承file类,定义具有新形式的子类,覆盖一些方法:

   1 class UppercaseFile(file):
   2     def write(self, astring):
   3         return file.write(self, astring.upper(  ))
   4     def writelines(self, strings):
   5         return file.writelines(self, map(string.upper,strings))
   6 
   7 upperOpen = UppercaseFile

To open such a file, we can call upperOpen just like a function, with the same arguments as the built-in open function. Because we don't override _ _init_ _, we inherit file's arguments, which are the same as open's.

使用上面的文件,使用upperOpen既可以, 具有同内置函数open(file)一样的的参数列表. 由于并未覆盖init函数,这里继承了file类的参数,并且同open(file)的参数列表要求的意志.

If we are using Python 2.1 or earlier, or if we need a classic class for whatever purpose, we can use automatic delegation:

如果使用Python 2.1以及更早版本,或则出于某种目的需要使用旧形式的类?,可以使用自动代理:

   1 class UppercaseFile:
   2     # Initialization needs to be explicit
   3     def _ _init_ _(self, file):
   4         # NOT self.file=file, to avoid triggering _ _setattr_ _ 
   5         self._ _dict_ _['file'] = file
   6 
   7     # Overrides aren't very different from the inheritance case:
   8     def write(self, astring):
   9         return self.file.write(astring.upper(  ))
  10     def writelines(self, strings):
  11         return self.file.writelines(map(string.upper,strings))
  12 
  13     # Automatic delegation is a simple and short boilerplate:
  14     def _ _getattr_ _(self, attr):
  15         return getattr(self.file, attr)
  16     def _ _setattr_ _(self, attr, value):
  17         return setattr(self.file, attr, value)
  18 
  19 def upperOpen(*args, **kwds):
  20     return UppercaseFile(open(*args, **kwds))

In this variant, upperOpen is called just as before but it separates the generation of the file object internally (done via the built-in open function) and its wrapping into the automatically delegating class (UppercaseFile).

对这个变化些类, 仍然可以使用upperOpen同前面的类一样。类内部实现分离了调用open函数产生新的文件和对UppercaseFile的代理包装两个步骤。

1.3. 讨论 Discussion

Automatic delegation, which the special methods _ _getattr and _ _setattr_ _ let us perform so smoothly, is a powerful and general technique. In this recipe, we show how to use it to get an effect that is almost indistinguishable from subclassing a built-in type, but in a way that also works with Python 2.1 and earlier. This technique also produces a classic class, just in case we want the classic object model's semantics even in newer versions of Python. Performance isn't quite as good as with real inheritance, but we get better flexibility and finer-grained control as compensation.

The fundamental idea is that each instance of our class holds an instance of the type we are wrapping (i.e., extending and/or tweaking). Whenever client code tries to get an attribute from an instance of our class, unless the attribute is specifically defined there (e.g., the write and writelines methods in this recipe), _ _getattr_ _ transparently shunts the request to the wrapped instance. In Python, methods are also attributes, accessed in just the same way, so we don't need to do anything more to access methods梩he approach used to access data attributes works for methods just as well. _ _setattr_ _ plays a similar role when client code sets an attribute. Remember that to avoid triggering _ _setattr_ _ from inside the methods you code, you must set values in self._ _dict_ _ explicitly. While Python calls _ _getattr_ _ only for attributes it does not find in the usual way, it calls _ _setattr_ _ for every attribute that is set (except for a few special ones such as _ _dict_ _ and _ _class_ _, held in the object itself and not in its dictionary).

Note that wrapping by automatic delegation does not work well with client or framework code that, one way or another, does type-testing. In such cases, it is the client or framework code that is breaking polymorphism and should be rewritten. Remember not to use type-tests in your own client code, as you probably do not need them anyway. See Recipe 5.11 for better alternatives.

In Python 2.2, you'll use automatic delegation less often, since you don't need it for the specific purpose of subclassing built-ins. However, delegation still has its place梚t is just a bit farther from the spotlight than in 2.1 and earlier. Although the new-style object model (which you get by subclassing built-ins) is almost always preferable, there are a few cases in which you should use classic classes because they are even more dynamic than new-style classes. For example, if your program needs to change an instance's _ _class_ _ on the fly, this is always allowed for instances of classic classes, but subject to constraints for instances of new-style classes. More importantly, delegation is generally more flexible than inheritance, and sometimes such flexibility is invaluable. For example, an object can delegate to different subobjects over time or even all at once (see Recipe 5.21), and inheritance doesn't offer anything comparable.

1.4. 参考 See Also

Recipe 5.11 and Recipe 5.21; PEP 253 (http://www.python.org/peps/pep-0253.html) describes in detail what there is to know about subtyping built-in types.