我有几个不同种类的对象(不同的函数名称,不同的签名),我对它们进行修补,以便有一种从不同函数访问它们的常用方法。简而言之,有一个调度程序可以获取我想要修补的对象,并根据它调用不同修补程序的对象类型。修补程序将向对象添加方法:
def patcher_of_some_type(object):
def target(self, value):
# do something and call self methods
object.target = types.MethodType(target, object)
# many more of these
随着程序变得越来越复杂,围绕对象(或对象类)的包装似乎更好。一些修补程序共享公共代码或相互关联。但我不控制对象创建,也不控制类创建。我只得到了这些物品。即使我能做到这一点,我只想包装(或修补)某些对象,而不是全部。
一个解决方案可能是为现有对象添加基类,但我不确定这是多么可维护和安全。还有其他解决方案吗?
答案 0 :(得分:11)
动态修改对象的类型是相当安全的,只要额外的基类是兼容的(如果不是,你会得到一个例外)。添加基类的最简单方法是使用3参数type
构造函数:
cls = object.__class__
object.__class__ = cls.__class__(cls.__name__ + "WithExtraBase", (cls, ExtraBase), {})
答案 1 :(得分:7)
基于另一个答案的comment,这是修补基类的另一种方法:
class Patched(instance.__class__, ExtraBase):
pass
instance.__class__ = Patched
答案 2 :(得分:0)
要将类添加到另一个类库,您可以执行以下操作:
def pacher_of_some_type(object):
#this class holds all the stuff you want to add to the object
class Patch():
def target(self, value):
#do something
#add it to the class' base classes
object.__class__.__bases__ += (Patch, )
但是这会影响这个类的所有对象,因为你实际上更改了类本身,这似乎不是你想要的...如果你只想修补一个实例,你可以继承原始类并改变实例类动态:
class PatchedClass(object.__class__):
def target(self, value):
#do whatever
object.__class__ = PatchedClass
在安全性和可管理性方面,我认为动态添加基类与动态添加一些函数一样可维护,并且更安全,因为你不太可能意外覆盖原始类的一些内部函数,因为新的基类class被添加到元组的末尾,这意味着它最后用于名称解析。如果您确实想要覆盖方法,请将它们添加到基类元组的开头(当然这不适用于子类方法)。不要问我是否动态更改实例的类是安全的,但是在一个简单的例子中它似乎不是一个问题:
class A():
def p(self): print 1
class B():
def p(self): print 2
a = A()
a.p() #prints 1
a.__class__ = B
a.p() #prints 2