文章来自《Python cookbook》.

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

::-- KenLai [2006-03-20 14:37:31]

1. 描述

Credit: Ken Seehof

1.1. 问题 Problem

You need to modify the class hierarchy of an instance object that has already been instantiated.

需要修改一个已经实例化的类的继承关系。

1.2. 解决 Solution

A rather unusual application of the mix-in concept lets us perform this task in Python 2.0 or later (with some limitations in Python 2.2):

一个不太寻常的程序要我们在Python 2.0及以后版本中完成这项工作。(在Python 2.2 中有一些限制):

   1 def adopt_class(klass, obj, *args, **kwds):
   2     're-class obj to inherit klass; call _ _init_ _ with *args, **kwds'
   3     # In Python 2.2, klass and obj._ _class_ _ must be compatible,
   4     # e.g., it's okay if they're both classic, as in the 'demo' function
   5     classname = '%s_%s' % (klass._ _name_ _, obj._ _class_ _._ _name_ _)
   6     obj._ _class_ _ = new.classobj(classname,  (klass, obj._ _class_ _), {})
   7     klass._ _init_ _(obj, *args, **kwds)
   8 
   9 def demo(  ):
  10     class Sandwich:
  11         def _ _init_ _(self, ingredients):
  12             self.ingredients = ingredients
  13         def _ _repr_ _(self):
  14             return ' and '.join(self.ingredients)
  15 
  16     class WithSpam:
  17         def _ _init_ _(self, spam_count):
  18             self.spam_count = spam_count
  19         def _ _repr_ _(self):
  20             return Sandwich._ _repr_ _(self) + self.spam_count * ' and spam'
  21 
  22     pbs = Sandwich(['peanut butter', 'jelly'])
  23     adopt_class(WithSpam, pbs, 2)
  24     print pbs

1.3. 讨论 Discussion

Sometimes class adoption, as illustrated by this recipe, is the cleanest way out of class hierarchy problems that arise when you wish to avoid module interdependencies (e.g., within a layered architecture). It's more often useful if you want to add functionality to objects created by third-party modules, since modifying those modules' source code is undesirable.

当您希望避免模块间的相互依赖,有时类组合,就像处方中的例子,就是最简洁的方法来避免发生类继承的问题 (比如,在分层的结构中)。 如果您希望给一个第三方模块创建的对象添加函数时这会显得比较实用,因为修改这些模块的源代码并不令人愉快。

In the following example, the programmer has these constraints:

在下面的例子中,程序员有这样一些限制:

There are several classes in objects.py, and more will be added in the future.

objects.py 定义了许多的类,以后还在加入继续加入。

objects.py must not import or know about graphics.py, since the latter is not available in all configurations. Therefore, class G cannot be a base class for the objects.py classes.

objects.py 不能import或者被 graphics.py 所知, 因为后定义的不能在所有情况下都可用。因此,类 G 不能成为 objects.py 中一个基类。

graphics.py should not require modification to support additional classes that may be added to objects.py.

graphics.py 不需要修改便能支持 objects.py 中新添加的类。

   1 #####################
   2 # objects.py
   3 class A(Base):
   4 ...
   5 class B(Base):
   6 ...
   7 def factory(...):
   8 ... returns an instance of A or B or ...
   9 
  10 ######################
  11 # graphics.py
  12 from oop_recipes import adopt_class
  13 import objects
  14 
  15 class G:
  16 ... provides graphical capabilities
  17 
  18 def gfactory(...):
  19     obj = objects.factory(...)
  20     adopt_class(G, obj, ...)
  21     return obj

Given the constraints, the adopt_class function provides a viable solution.

在上面的限制下,adopt_class 函数提供了一个可行的解决方案。

In Python 2.2, there are compatibility limitations on which classes can be used to multiply inherit from (otherwise, you get a "metatype conflict among bases" TypeError exception). These limitations affect multiple inheritance performed dynamically by means of the new.classobj function (as in this recipe) in the same way as they affect multiple inheritance expressed in the more usual way.

Python 2.2中,又一个多重继承的兼容性问题(因此,您会得到 "metatype conflict among bases" 异常)。 这些限制动态下的多重继承要依靠 new.classobj 函数(就像处方中的),同样对以更平常的方式表示多重继承产生了影响。

Classic classes (classes with no built-in type among their ancestors, not even the new built-in type object) can still be multiply inherited from quite peaceably, so the example in this recipe keeps working. The example given in the discussion will also keep working the same way, since class G is classic. Only two new-style classes with different built-in type ancestors would conflict.

经典类(类定义的括号中没有父类,也没有新的内建类型 object)也能正常的多重继承,所以处方中的例子也能运行。讨论部分中给出的也能运行,因为G 是一个经典类。只有两个以不同内建类型作为父类时才会产生冲突。

1.4. 参考 See Also

The Library Reference section on built-in types, especially the subsections on special attributes and functions.

Library Reference 中关于内建类型的小节,特别是关于特殊属性与函数的部分。