В этом образце есть несколько других проблем, но, чтобы ответить на вопрос, все, что вам нужно сделать, это когда вы оборачиваете свойство
Когда вы оборачиваете свойство, вместо этого оборачивайте его метод __get__:
class MyObject(object):
def method(self):
print "method called on %s" % str(self)
@property
def result(self):
return "Some derived property"
def common(self, a=None):
print self
def my_decorator(func):
def _wrapped(*args, **kwargs):
print "Calling decorated function %s" % func
return func(*args, **kwargs)
return _wrapped
class WrappedObject(object):
def __init__(self, cls):
for attr, item in cls.__dict__.items():
if attr != '__init__' and callable(item):
setattr(cls, attr, my_decorator(item))
elif isinstance(item, property):
new_property = property(my_decorator(item.__get__), item.__set__, item.__delattr__)
setattr(cls, attr, new_property)
self._cls = cls
def __call__(self, *args, **kwargs):
return self._cls(*args, **kwargs)
inst = WrappedObject(MyObject)()
Это самая простая модификация вашего кода, которая выполняет эту работу.Однако я бы изменил его на динамически подкласс класса, который он оборачивает, чтобы избежать перезаписи его атрибутов.Вы можете создать подкласс программным способом, просто вызвав тип с именем, кортежем с базами и dict в качестве параметров.
edit - изменение кода на класс с подклассом
Фактически, подклассданный класс почти не требует модификации данного кода, но для указанного мной вызова type
.Я только что проверил это здесь - измените ваш класс WrappedObject на:
class WrappedObject(object):
def __init__(self, cls):
dct = cls.__dict__.copy()
for attr, item in dct.items():
if attr != '__init__' and callable(item):
dct[attr] = my_decorator(item)
elif isinstance(item, property):
new_property = property(my_decorator(item.__get__), item.__set__, item.__delattr__)
dct[attr] = new_property
self._cls = type("wrapped_" + cls.__name__, (cls,), dct)
def __call__(self, *args, **kwargs):
return self._cls(*args, **kwargs)