[英]Defining a “property”-like decorator in Python 2.7
I'm trying to write a decorator that works like @property, but running into some problems. 我正在尝试编写一个像@property一样工作的装饰器,但遇到了一些问题。
class Dec(object):
def __init__(self, fn):
self._fn = fn
self._before = None
@property
def before(self)
return self._before
@before.setter
def before(self, fn):
self._before = fn
def __call__(self, *args, **kwargs):
self._before(*args, **kwargs)
self._fn(*args, **kwargs)
def withbefore(fn):
return Dec(fn)
Its a simple chaining decorator. 它是一个简单的链式装饰器。 The @property/@.setter syntax is exactly what I'm trying to clone.
@property / @。setter语法正是我想要克隆的。
This works: 这有效:
@withbefore
def foo():
...
@foo.before
def beforefoo():
...
But on a class it doesn't: 但在课堂上却没有:
class Weee(object):
@withbefore
def do_stuff(self):
pass
@do_stuff.before
def before_do_stuff(self):
pass
It raises an import error. 它引发了导入错误。
TypeError: 'NoneType' object is not callable
How can i correctly emulate @property/.{setter,getter,deleter} ? 我怎样才能正确模仿@property /。{setter,getter,deleter}?
Actually, it raises a TypeError. 实际上,它引发了一个TypeError。
Anyway, I got the same error when running your decorator with functions, too. 无论如何,我在使用函数运行装饰器时也遇到了同样的错误。 It happens because, when you decorate a function with
@foo.before
, it will call the self._before
function with the decorated function as parameter. 之所以发生这种情况,是因为当你使用
@foo.before
修饰一个函数时,它将使用修饰函数作为参数调用self._before
函数。 Since self._before
is None
, it will raise the error. 由于
self._before
为None
,因此会引发错误。
There are various solutions for it. 它有各种解决方案。 My favorite is to set a different default value to
self._before
- a function which will set the self._before
value: 我最喜欢的是为
self._before
设置一个不同的默认值 - 一个设置self._before
值的函数:
class Dec(object):
def __init__(self, fn):
self._fn = fn
def setbefore(b):
self._before = b
self._before = self.default_before = setbefore
Of course, this function should not be called when the Dec
object is called so we change the __call__
method: 当然, 调用
Dec
对象时不应调用此函数,因此我们更改了__call__
方法:
def __call__(self, *args, **kwargs):
if self._before != self.default_before:
self._before(*args, **kwargs)
self._fn(*args, **kwargs)
Sincerely, I think you'd be better off with: 真诚地,我认为你会更好:
from functools import wraps
def withbefore(fn):
def dec(bef):
fn._before_fn = bef
return bef
@wraps(fn)
def _wrapper(*args, **kwargs):
fn._before_fn(*args, **kwargs)
return fn(*args, **kwargs)
_wrapper.before = dec
return _wrapper
It is more compact, more Pythonic and should work OK for all cases. 它更紧凑,更Pythonic,应该适用于所有情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.