文章来自《Python cookbook》.

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

::-- KenLai [2006-03-18 09:40:36]

描述

Credit: Brett Cannon

问题 Problem

You want to add a method to a class at an arbitrary point in your code for highly dynamic customization.

希望通过在代码任意地方为一个类添加一个方法来实现高动态定制

解决 Solution

The best way to perform this task works for both classic and new-style classes:

在经典或新风格类中完成任务的最佳方法:

   1 def funcToMethod(func, clas, method_name=None):
   2     setattr(clas, method_name or func._ _name_ _, func)

If a method of the specified name already exists in the class, funcToMethod replaces it with the new implementation.

如果方法的名称已经存在与类中,funcToMethod将用新的方法替换原来的。

讨论 Discussion

Ruby can add a method to a class at an arbitrary point in your code. I figured Python must have a way for allowing this to happen, and it turned out it did. There are several minor possible variations, but this recipe is very direct and compact, and works for both classic and new-style classes. The method just added is available instantly to all existing instances and to those not yet created. If you specify method_name, that name is used as the method name; otherwise, the method name is the same as the name of the function.

Ruby能在您代码的任意位置为一个类添加方法。我认为Python也应该能够通过某种方法完成,最后的确是这样的。虽然我们还有一些其他可能的方法,但这个处方非常直接简洁,并且在经典和新风格的类都可以使用。添加的方法能够立即在所有已存在的实体中使用,还有那些还没有创建的。如果您指定了方法名,那些这个名称就将作为此方法的名称使用;否则,方法名称与函数的名称相同。

You can use this recipe for highly dynamic customization of a running program. On command, you can load a function from a module and install it as a method of a class (even in place of another previous implementation), thus instantly changing the behavior of all existing and new instances of the class.

您可以使用此处方为运行的程序实现高动态定制。也就是说,您可以从一个模块中读取一个函数,并把它作为一个类方法加载(甚至在其他方法的执行中),因此能立即改变所有已经存在实体和新对象的行为。

One thing to make sure of is that the function has a first argument for the instance that will be passed to it (which is, conventionally, always named self). Also, this approach works only if func is a Python function, not a built-in or callable. For example, a built-in such as math.sin can be installed with this recipe's funcToMethod function. However, it doesn't turn into a method; it remains exactly the same, regardless of whether you access it as an attribute of a class or of an instance. Only true Python functions implicitly mutate into methods (bound or unbound as appropriate) when installed and accessed this way.

要确认的事是,函数的第一个参数将会传递给实体本身(也就是习惯上命名为self的参数)。所以,这个方法只能用于Python函数而不是内建的。比如:像math.sin这样的内建函数可以用此方法的funcToMethod函数。可以,他并不会成为一个方法。不管您作为一个方法还是实体都是相同的。只有真正的Python函数才能使用此方法成为一个类方法(绑定或者未绑定)。

For classic classes, you can use a different approach for installing a callable as a method of a class:

对于经典风格的类,您可以使用一种其他的方法把一个函数加载为类方法:

   1 def callableToMethod(func, clas, method_name=None):
   2     import new
   3     method = new.instancemethod(func, None, clas)
   4     setattr(clas, method_name or func._ _name_ _, method)

Now func can be any callable, such as an instance of any class that supplies a _ _call_ _ special method, a built-in, or a bound method.

现在func能够被随时调用,比如任何支持特殊方法_ _call_ _的类实体,内建,或一个绑定的方法。

The name of the instancemethod function of the new module may be slightly misleading. The function generates both bound and unbound methods, depending on whether the second argument is None (unbound) or an instance of the class that is the third argument. This function, however, works only with classic classes, not with new-style classes. See http://www.python.org/doc/current/lib/module-new.html for all the details (there's not much more to it than this, though).

new模块中的instancemethod函数的名字可能会产生一些误解。这个函数由第二个参数是None(未绑定)或者第三个参数指定的一个类的实体来决定产生绑定与未绑定的方法。而这个函数只适用于经典风格的类。参看http://www.python.org/doc/current/lib/module-new.html了解细节。

参考 See Also

The Library Reference section on the new module.

库参考中关于new模块部分。