Мне нужно написать класс для переноса классов из сторонних пакетов. Обычно у стороннего класса есть методы, которые возвращают экземпляры стороннего класса. Обернутые версии этих методов должны преобразовывать эти экземпляры в экземпляры обернутого класса, но я не могу заставить это работать. Я использую Python 2.7 с классами нового стиля.
На основе создайте класс-оболочку для вызова функции pre и post вокруг существующих функций?, у меня есть следующее.
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
, как ожидалось.
Извините, но я не ищу следующие альтернативные подходы:
- Патч обезьяны. Моя кодовая база нетривиальна, и я не знаю, как обеспечить распространение патча через сеть операторов импорта.
- Написание отдельных методов-оболочек для всех этих хитрых методов для каждого стороннего пакета. Их слишком много.
ETA: есть пара полезных ответов, которые ссылаются на базовый атрибут _obj
вне класса Wrapper
. Однако смысл этого подхода в расширяемости, поэтому эта функциональность должна быть внутри класса Wrapper
. myfun
должен вести себя так, как ожидается, без ссылки на _obj
в своем определении.