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