我有一个班级ABC
,里面有一个函数someFunction
。
我不想搞砸someFunction
的代码,因此我用@MyDecorator
包装它。当我致电MyDecorator
时,ABC
如何修改班级someFunction
的属性?
class ABC(object):
def __init__(self):
self.someProperty = "Initial value"
@MyDecorator
def someFunction(self):
print "Hello world"
class MyDecorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
# ...???
return self.func(*args, **kwargs)
abc = ABC()
abc.someFunction() # When calling someFunction(), abc.someProperty would be updated
答案 0 :(得分:1)
您可以尝试:
class MyDecorator(object):
def __init__(self, func):
self.func = func
def __call__(self, instance, *args, **kwargs):
instance.someProperty = "New value"
return self.func(instance, *args, **kwargs)
def __get__(self, instance, owner):
if instance is None:
return self
return self.__call__.__class__(self, instance)
class ABC(object):
def __init__(self):
self.someProperty = "Initial value"
@MyDecorator
def someFunction(self):
print("Hello world")
MyDecorator
现在是descriptor,因为它实现了__get__
。
当通过某个类或该类的实例访问MyDecorator
的任何实例的属性时,将调用__get__
。
__get__
将在参数instance
中收到该所有者对象的实例,从那里我们可以返回instancemethod
的新实例,该实例将隐式接收instance
:
>>> abc.someFunction.__class__
<type 'instancemethod'>
>>> abc.someFunction.__class__.__doc__
'instancemethod(function, instance, class)\n\nCreate an instance method object.'
>>>
它需要function
,基本上任何可调用对象都可以使用,因为MyDecorator
是类,__call__
会修改自己的self
。
行动中:
>>> abc = ABC()
>>> abc.someProperty
'Initial value'
>>> abc.someFunction()
Hello world
>>> abc.someProperty
'New value'
>>>
请注意,在Python 2.X中,MyDecorator
必须是继承object
或无法工作的新式类。
答案 1 :(得分:0)
您需要在文件中先前定义MyDecorator,而不是在使用它时,或者您得到“NameError:name'MyDecorator'未定义”。
当我说“装饰者应该返回一个函数”时,我错了。这适用于用作装饰器的函数,如我的示例所示。但是,当使用类时,它不必返回函数。它返回该类中的对象。如果“类MyDecorator”被命名为“类MyModifiedFunction”而不是混淆,因为类的一个元素被用作装饰函数。
通常,装饰器返回的函数将调用原始函数。你的没有。如果您想完全替换someFunction而不是仅修改它,则不必如此。
您不需要将MyDecorator设为类。你可以把它变成一个功能。这是一个例子:
def MyDecorator(original_function):
def replacement_function(*args, **kwargs):
args[0].some_property = some_new_value
return(original_function(*args, **kwargs))
return(replacement_function)
按照代码的前半部分进行操作,您可以在其中定义类ABC
。
请注意,当它显示return(original_function(*args, **kwargs))
时,它正在运行原始函数并返回原始函数返回的任何内容。如果原始函数返回一个对象,它将返回该对象。然而,当它说return(replacement_function)
它正在做一些完全不同的事情时:它当时没有运行替换功能;它只是将函数作为返回值返回。装饰者必须返回一个函数。
(@ dano:好的。我认为我修好了。)
以上是更完整形式的上述建议:
def MyDecorator(original_function):
def replacement_function(*args, **kwargs):
args[0].some_property = 'Modified value'
return(original_function(*args, **kwargs))
return(replacement_function)
class ABC(object):
def __init__(self):
self.some_property = "Initial value"
@MyDecorator
def some_function(self):
print "Hello world"
abc = ABC()
abc.some_function() # When calling some_function(), abc.some_property wou
要更新
print "some property is", abc.some_property
我跑了这个并且它有效;它打印
Hello world
some property is Modified value
所以这验证它确实修改了abc中的some_property。它作为args[0].some_property
访问,因为当调用修饰函数(作为对象方法)时,self
作为第一个参数传入。