用Python完全包装一个对象

Sma*_*ery 33 python reflection

我想完全包装一个对象,以便所有属性和方法请求转发到它包装的对象,但也覆盖我想要的任何方法或变量,以及提供我自己的一些方法.这个包装类应该作为现有类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)
Run Code Online (Sandbox Code Playgroud)

但我不是那个熟悉的覆盖__getattr__,__setattr__并且__hasattr__,所以我不知道如何获得这一权利.

Ale*_*lli 38

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

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

    def overriddenMethod(self):
        ...
Run Code Online (Sandbox Code Playgroud)

以这种方式工作,即通过重新分配自己__class____dict__以这种方式,你只需要提供你的覆盖 - Python的正常属性获取和设置机制将完成剩下的工作...... 主要是.

只有在baseObject.__class__定义时才会遇到麻烦__slots__,在这种情况下多重继承方法不起作用,你确实需要繁琐__getattr__(正如其他人所说的那样,至少你不必担心它会被你的属性调用'重新覆盖,因为它不会! - ),__setattr__(更大的痛苦,因为它会被称为每个属性),等等; 制作isinstance和特殊方法的工作需要艰苦而繁琐的细致工作.

本质上,__slots__意味着一个类是一个特殊的,每个实例都是一个轻量级的"值对象",不会受到进一步复杂的操​​作,包装等的影响,因为需要为该类的每个实例保存几个字节会覆盖所有正常的关注点.灵活性等; 因此,以同样流畅和灵活的方式处理这些极端罕见的类,因为你可以处理99%以上的Python对象,这并不奇怪,这真的很痛苦.那么你需要处理__slots__(为了那些极端情况而编写,测试,调试和维护数百行代码),还是在十几行的99%解决方案就足够了? - )

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

  • @bgbg,您的方法包装了*类*,而不是OP请求的*对象*。 (2认同)

小智 6

请查看http://code.activestate.com/recipes/577555-object-wrapper-class/以获取完整的代码,包括重要的注释。归结为:

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)
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的方法,您不必检查attr是否在dict中。仅当属性不在字典中时才调用__getattr__。 (2认同)

小智 5

__getattr__ 它的优点是仅在属性不存在时调用,因此您不需要显式列表 - 您未定义的任何内容都将自动被代理。

__setattr__比较棘手,因为它总是被调用。确保使用超类调用或object.__setattr__在设置自己的属性时;使用setattr()inside__setattr__会导致无限递归。

影响 isinstance 的最后一点非常困难。您可以通过对包装器实例的 . __class__变量(但这也会覆盖类字典解析顺序),或者通过使用元类动态构造您的包装器类型。由于 isinstance 在 Python 代码中非常少见,实际上试图欺骗它似乎有点过分。

有关特殊属性访问方法的更多信息。

关于它们的更多信息,以及一些有关元类的帮助。