用Python完全包装对象

用Python完全包装对象,python,reflection,Python,Reflection,我想完全包装一个对象,这样所有的属性和方法请求都会被转发到它包装的对象,但也会覆盖我想要的任何方法或变量,并提供一些我自己的方法。这个包装类应该100%地显示为现有类(isinstance必须像它实际是类一样工作),但是子类化本身并不会减少它,因为我想包装一个现有对象。Python中有什么解决方案可以做到这一点吗?我的想法大致如下: class ObjectWrapper(BaseClass): def __init__(self, baseObject): self.b

我想完全包装一个对象,这样所有的属性和方法请求都会被转发到它包装的对象,但也会覆盖我想要的任何方法或变量,并提供一些我自己的方法。这个包装类应该100%地显示为现有类(
isinstance
必须像它实际是类一样工作),但是子类化本身并不会减少它,因为我想包装一个现有对象。Python中有什么解决方案可以做到这一点吗?我的想法大致如下:

class ObjectWrapper(BaseClass):
    def __init__(self, baseObject):
        self.baseObject = baseObject

    def overriddenMethod(self):
        ...

    def myOwnMethod1(self):
        ...

    ...

    def __getattr__(self, attr):
        if attr in ['overriddenMethod', 'myOwnMethod1', 'myOwnMethod2', ...]
            # return the requested method
        else:
            return getattr(self.baseObject, attr)

但是我不太熟悉重写
\uuu getattr\uuuu
\uuu setattr\uuuu
\uu hasattr\uuuu
,所以我不知道如何正确地实现它。

\uu getattr\uuuuu
的优点是,它只在属性不存在时被调用,因此,您不需要显式列表——任何未定义的内容都将自动得到代理

\uuuu setattr\uuuuu
更复杂,因为它总是被调用。确保在设置自己的属性时使用超类调用或
对象;在
中使用
setattr()
将导致无限递归

最后一位,影响isinstance,是非常困难的。您可以通过对包装器实例的。
\uuuuu class\uuuu
变量进行赋值(但这也会覆盖类字典解析顺序),或者使用元类动态构造包装器类型。由于iInstance在Python代码中非常罕见,因此试图欺骗它似乎有些过分


所说的“现有对象”是指另一个类的实例吗?听起来好像您只需要从基类继承。创建新对象时,请传入基对象的详细信息,或在新类中添加一个方法,该方法将基类实例的数据复制到自身中。

注意:这个答案非常古老,在现代python上可能不起作用。我相信它曾经在2.6上工作过

从这个开始,把循环中的东西搞乱,以满足您的需要:

import inspect
class Delegate(object):
    def __init__(self, implementation):
        self.__class__ = implementation.__class__
        for n, m in inspect.getmembers(implementation, callable):
            if not n.startswith('_'):
                setattr(self, n, m)

包装非新样式对象的功能留给读者作为练习:)

在大多数情况下,最简单的方法可能是:

class ObjectWrapper(BaseClass):
    def __init__(self, baseObject):
        self.__class__ = type(baseObject.__class__.__name__,
                              (self.__class__, baseObject.__class__),
                              {})
        self.__dict__ = baseObject.__dict__

    def overriddenMethod(self):
        ...
以这种方式工作,即通过以这种方式重新分配self的
\uuuuu类\uuuuuuu
\uuuuuuu dict\uuuuuu
,您只需提供覆盖——Python的正常属性获取和设置机制将完成其余工作。。。大部分

只有当
baseObject.\uuu class\uuuuuuuu
定义了
\uuuu slots\uuuuuuuuu
时,您才会遇到麻烦,在这种情况下,多重继承方法不起作用,您确实需要麻烦的
\uuu getattr\uuuuuuuuuuu
(正如其他人所说的,至少您不必担心它会被覆盖的属性调用,因为它不会这样!),
\uuuuu setattr\uuuuuu
(更痛苦的是,每个属性都会调用它),等等;而要使
isinstance
和特殊方法发挥作用,需要艰苦而繁琐的详细工作

本质上,
\uuuuuuuuuu slots\uuuuuuuuuu
意味着一个类是一个特殊的类,每个实例都是一个轻量级的“值对象”,不会受到进一步复杂的操作、包装等的影响,因为需要为该类的每个实例节省几个字节,这压倒了所有关于灵活性等的正常关注;因此,以与处理99%以上Python对象相同的平滑灵活的方式处理如此极端、罕见的类确实是一件痛苦的事情,这并不奇怪。那么,您是否需要处理
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu


还应注意,这可能会导致内存泄漏,因为创建子类会将该子类添加到基类的子类列表中,并且在子类的所有实例都是GC的情况下不会删除该子类。

以下方法与类似,但对我来说更具可读性:

我没有创建一个新类,而是创建了一个类函数,用于实例化底层对象并覆盖所需的函数,如下所示:

class C1:
    def __init__(self, p):
        self.p = p
    def f(self):
        print("This is C1, p=%s" % self.p)

def C2(p):
    c = C1(p)
    def new_f():
        print("This is C2, p is %s" % c.p)
    c.f = new_f
    def g(param):
        print("This is C2.g(%s), p is %s" % (param, c.p))
    c.g = g
    return c

c1 = C1('abc')
c1.f()

c2 = C2('cde')
c2.f()
c2.g('xyz')
输出:

This is C1, p=abc

This is C2, p is cde
This is C2.g(xyz), p is cde
请查看完整的代码,包括重要的注释。归结起来是:

class Wrapper(object):
    def __init__(self, obj):
        self._wrapped_obj = obj
    def __getattr__(self, attr):
        if attr in self.__dict__:
            return getattr(self, attr)
        return getattr(self._wrapped_obj, attr)

要是这么简单就好了。我正在包装的类是一个第三方类,我相信它是用C编写的。这使得整个堆变得更加困难(当我们更新到第三方库的新版本时,它可能会发生变化,我宁愿不必再修改代码了。)我有一种感觉,可能就是这样。。因此,基本上您希望创建一个现有类的接口。在这种情况下,你的建议可能是一种巧妙的方法。祝你好运:-)看到我的答案了。有人能提供一个更深入地解释这种方法的链接吗?你怎么知道哪个dict首先被分配?调用_uinit _;中的那个?还是隐式的?我觉得这种方法太冗长,有点神秘。你觉得怎么样?@BG,你的方法是包装一个类,而不是像OP要求的那样包装一个对象。这是一个很好的方法,您不必检查attr是否在dict中。仅当atribute不在dict中时才会调用
\uuuu getattr\uuuu
。这有一个微妙的问题,即如果
\uu getattr\uuuu
没有为不存在的属性引发AttributeError,那么hasattr将返回True,其他一些代码可能会尝试访问该属性。所以hasattr(Wrapper({}),'foo')将是真的,而这显然不是您想要的。您应该添加行
def\uu setattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu=obj
to。我尝试时失败:
self.\uuuuu类\uuuuu=implementation.\uuuuu类\uuuuuuuuu类型错误:\uuuuu类\uuuuu分配仅支持堆类型或ModuleType子类
考虑到响应时间为9年,可能性为t