包装一个类,其方法返回该类的实例 [英] Wrapping a class whose methods return instances of that class
问题描述
我需要编写一个类来包装来自第三方包的类.通常,第三方类具有返回第三方类实例的方法.这些方法的包装版本必须将这些实例转换为包装类的实例,但我无法使其工作.我将 Python 2.7 与新式类一起使用.
I need to write a class to wrap classes from third-party packages. Usually, the third-party class has methods that return third-party class instances. The wrapped versions of these methods have to convert those instances into instances of the wrapped class, but I can't make it work. I'm using Python 2.7 with new-style classes.
基于 创建一个包装类来围绕现有函数调用 pre 和 post 函数?,我有以下内容.
Based on Create a wrapper class to call a pre and post function around existing functions?, I've got the following.
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()
不会引发错误,但不会添加1 到 wr2.data
按预期.
Now why on earth does theirfun()
work the first time, but not the second time? Both wr0
and wr2
are of type Wrapped, and invoking wr2.theirfun()
doesn't raise an error, but it doesn't add 1 to wr2.data
as expected.
抱歉,我不在寻找以下替代方法:
Sorry, but I am not looking for the following alternative approaches:
- 猴子补丁.我的代码库很重要,我不知道如何确保补丁通过导入语句网络传播.
- 为每个第三方包的所有这些棘手方法编写单独的包装方法.太多了.
ETA:有几个有用的答案引用了 Wrapper
类之外的底层 _obj
属性.但是,这种方法的重点是可扩展性,因此此功能需要在 Wrapper
类中.myfun
需要在其定义中不引用 _obj
的情况下按预期运行.
ETA: There are a couple helpful answers that reference the underlying _obj
attribute outside of the Wrapper
class. However, the point of this approach is extensibility, so this functionality needs to be inside the Wrapper
class. myfun
needs to behave as expected without referencing _obj
in its definition.
推荐答案
问题在于您在 Wrapped
类中实现了 myfun
.你只更新类'实例的data
成员,但是包装类'(ClassToWrap
instance ie _obj
) data
成员已过时,使用来自 theirfun
的 prev 调用的值.
The problem is with your implementation of myfun
in the Wrapped
class. You only update the data
member of the class' instance, but the wrapped class' (ClassToWrap
instance i.e. _obj
) data
member is obsolete, using a value from the prev call of theirfun
.
您需要在两个实例之间同步数据值:
You need to synchronise the data values across both instances:
class Wrapper(object):
...
def __setattr__(self, attr, val):
object.__setattr__(self, attr, val)
if getattr(self._obj, attr, self._obj) is not self._obj: # update _obj's member if it exists
setattr(self._obj, attr, getattr(self, attr))
class Wrapped(Wrapper):
...
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
# 3
wr4 = wr3.myfun()
print wr4.data
# 4
wr5 = wr4.theirfun()
print wr5.data
# 5
这篇关于包装一个类,其方法返回该类的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!