我需要从第三方包装类。通常,第三方类具有返回第三方类实例的方法。这些方法的包装版本必须将这些实例转换为包装类的实例,但我无法使其工作。我将Python2.7与新样式的类一起使用。在
基于Create a wrapper class to call a pre and post function around existing functions?,我得到了以下内容。在
import copy
class Wrapper(object):
__wraps__ = None
def __init__(self, obj):
if self.__wraps__ is None:
raise TypeError("base class Wrapper may not be instantiated")
elif isinstance(obj, self.__wraps__):
self._obj = obj
else:
raise ValueError("wrapped object must be of %s" % self.__wraps__)
def __getattr__(self, name):
orig_attr = self._obj.__getattribute__(name)
if callable(orig_attr):
def hooked(*args, **kwargs):
result = orig_attr(*args, **kwargs)
if result == self._obj:
return result
return self.__class__(result)
return hooked
else:
return orig_attr
class ClassToWrap(object):
def __init__(self, data):
self.data = data
def theirfun(self):
new_obj = copy.deepcopy(self)
new_obj.data += 1
return new_obj
class Wrapped(Wrapper):
__wraps__ = ClassToWrap
def myfun(self):
new_obj = copy.deepcopy(self)
new_obj.data += 1
return new_obj
obj = ClassToWrap(0)
wr0 = Wrapped(obj)
print wr0.data
>> 0
wr1 = wr0.theirfun()
print wr1.data
>> 1
wr2 = wr1.myfun()
print wr2.data
>> 2
wr3 = wr2.theirfun()
print wr3.data
>> 2
那么,为什么theirfun()
第一次起作用,第二次却不行?wr0
和wr2
都是Wrapped类型,调用wr2.theirfun()
不会引发错误,但不会像预期的那样向wr2.data
添加1。在
抱歉,但我不是在寻找以下替代方法:
ETA:有几个有用的答案引用了Wrapper
类之外的底层_obj
属性。但是,这种方法的重点是可扩展性,因此这个功能需要在Wrapper
类中。myfun
需要按预期运行,而不在其定义中引用{
问题在于}的实例。您的
myfun
中的赋值new_obj.data += 1
。它的问题是new_obj
是Wrapped
的实例,而不是{Wrapper
基类只支持在代理对象上查找属性。它不支持属性赋值。增广赋值同时做到了这两个方面,所以它不能完全正确地工作。在您可以通过稍微改变一下
myfun
使其工作:解决这个问题的另一种方法是在
Wrapper
中添加一个__setattr__
方法,但是让它正常工作(不干涉代理类自身的属性)会有点尴尬。在与您当前的问题无关,您还可能泄漏
^{pr2}$hooked
包装函数中的包装对象。如果您调用的方法返回被调用的对象(例如,方法didreturn self
),那么您当前返回的对象是unwrapped。您可能需要将return result
更改为return self
,以便返回当前包装器。您可能还需要检查返回值,看看它是否是一个可以包装的类型。当前,如果一个方法返回字符串或数字或其他任何内容而不是包装类型的实例,则代码将失败。在问题在于您在
Wrapped
类中实现myfun
。您只更新了类instance的data
成员,但是包装类(ClassToWrap
实例,即_obj
)data
成员是过时的,使用的是theirfun
的前一个调用。在您需要在两个实例之间同步数据值:
相关问题 更多 >
编程相关推荐