将基类添加到python中的现有对象

Posted

技术标签:

【中文标题】将基类添加到python中的现有对象【英文标题】:Adding base class to existing object in python 【发布时间】:2012-06-18 00:52:50 【问题描述】:

我有几个不同类型的对象(不同的函数名称,不同的签名),我对它们进行了修补,以便有一种从不同函数访问它们的通用方法。简而言之,有一个调度程序接收我要修补的对象,并根据对象类型调用不同的修补程序。修补程序将为对象添加方法:

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

随着程序变得越来越复杂,围绕对象(或对象类)进行包装似乎是更好的主意。一些修补程序共享公共代码或相互关联。但我不控制对象的创建,也不控制类的创建。我只得到对象。即使我能做到这一点,我也只想包装(或修补)某些对象,而不是全部。

一种解决方案可能是将基类添加到现有对象,但我不确定这是多么可维护和安全。还有其他解决方案吗?

【问题讨论】:

所以这些类不是你定义的? 不,这些类是在我无法控制的库中定义的。我可以从所有类创建包装器,但这仅适用于我实例化的对象,不适用于库实例化的对象。如果我修补库,则会发生相反的情况:所有对象都已修补,而我只想修补其中的一些。最后,如果我包装一些对象,我需要保留自己的数据结构来引用它们。这就是为什么我现在正在修补我想要的对象。 我会定义一个包装类来保存对象。需要有不同类型的共享公共代码的包装器可以通过拥有一个基本包装器类并从中派生专门的版本来处理。基本的 OOP 东西... @martineau:我不明白你关于我的问题的建议。我建议创建一个包装类(一个他们专门的)版本,我要问的是如何以一种健壮且可维护的方式将所有这些类方法添加到现有对象中。 @Hernan: 包装类的整个想法是它充当proxy 或与某些底层对象(委托)的接口,因此不需要添加方法来该对象(大多数语言无论如何都做不到)。除此之外,一般来说,可能无法以“稳健且可维护的方式”执行您所要求的操作,因此即使您应该避免这样做。 【参考方案1】:

动态修改对象的类型是相当安全的,只要额外的基类是兼容的(如果不兼容,你会得到一个异常)。添加基类的最简单方法是使用 3 参数 type 构造函数:

cls = object.__class__
object.__class__ = cls.__class__(cls.__name__ + "WithExtraBase", (cls, ExtraBase), )

【讨论】:

使用类型(请只使用type而不是object.__class__.__class__,顺便说一句,旧式类会失败!)只有在需要设置类名时才需要,否则你可以做class AnyNameHere(cls, ExtraBase): pass 更易读。【参考方案2】:

基于另一个答案上的comment,这是修补基类的另一种方法:

class Patched(instance.__class__, ExtraBase):
    pass

instance.__class__ = Patched

【讨论】:

这真是太棒了!但是,它似乎确实将类名更改为 Patched。你可以通过添加一行来解决这个问题:Patched.__name__ = instance.__class__.__name__【参考方案3】:

要将一个类添加到另一个类库,您可以执行以下操作:

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 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

【讨论】:

以上是关于将基类添加到python中的现有对象的主要内容,如果未能解决你的问题,请参考以下文章

通过 C++ 中的 std 迭代器将基类转换为派生

将基类的对象传递给派生类的引用函数

使用shared_ptr将基类引用值复制到映射

将基类转换为派生类[重复]

如何将基类的未知子类放在一个数据结构中并在 C++ 中调用重写的基类函数

我是不是将基类与超类一起继承以进行多重继承?