用Python完全包装对象

2024-05-23 21:33:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望完全包装一个对象,以便所有属性和方法请求都被转发到它包装的对象,同时也覆盖我想要的任何方法或变量,以及提供一些我自己的方法。这个包装类应该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)

但我不太熟悉重写__getattr____setattr____hasattr__,所以我不知道如何正确地实现这一点。


Tags: 对象方法selfreturn属性def解决方案子类
3条回答

__getattr__的优点是只有在属性不存在时才调用它,因此不需要显式列表——任何未定义的内容都将自动获得代理。

__setattr__更复杂,因为它总是被调用。确保在设置自己的属性时使用超类调用或object.__setattr__;在__setattr__内使用setattr()将导致无限递归。

最后一个位,影响isinstance,是非常困难的。您可以通过对包装器实例的.__class__变量(但这也会重写类字典的解析顺序)的辅助,或者通过使用元类动态构造包装器类型来完成此任务。由于isinstance在Python代码中非常罕见,所以实际上试图欺骗它似乎有些过头了。

More information on special attribute access methods.

Even more information on them, plus some help with metaclasses.

请查看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)

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

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的__class____dict__,您只需要提供覆盖——Python的常规属性获取和设置机制将完成其余的工作。。。大部分

只有当baseObject.__class__定义了__slots__时,您才会遇到麻烦,在这种情况下,多重继承方法不起作用,而且您确实需要繁琐的__getattr__(正如其他人所说,至少您不必担心它将被调用时具有您重写的属性,因为它不会!-),__setattr__(一个更大的痛苦,因为每个属性都需要调用它)等;使isinstance和特殊方法工作需要艰苦和繁琐的详细工作。

本质上,__slots__意味着一个类是一个特殊的,每个实例都是一个轻量级的“值对象”,不需要进行更复杂的操作、包装等,因为每个类实例需要节省几个字节,这覆盖了所有关于灵活性等的正常关注;因此处理以同样平滑灵活的方式处理99%以上的Python对象,这种极端、罕见的类确实是一种痛苦。那么,您需要处理__slots__(到编写、测试、调试和维护数百行代码的程度,仅仅是为了那些角落的情况),还是说,用6行99%的解决方案就足够了?-)

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

相关问题 更多 >