包装一个类,其方法返回该类的实例 [英] Wrapping a class whose methods return instances of that class

查看:67
本文介绍了包装一个类,其方法返回该类的实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要编写一个类来包装来自第三方包的类.通常,第三方类具有返回第三方类实例的方法.这些方法的包装版本必须将这些实例转换为包装类的实例,但我无法使其工作.我将 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() 第一次可以工作,但第二次不行?wr0wr2 都是 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:

  1. 猴子补丁.我的代码库很重要,我不知道如何确保补丁通过导入语句网络传播.
  2. 为每个第三方包的所有这些棘手方法编写单独的包装方法.太多了.

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆