装饰器不应该有副作用吗?
我在编辑,因为最开始的代码让人困惑。
我本以为这两件事是一样的,
#I would use either of these
#Option 1
def bar(*args):
pass
foo = deco(bar)
#Option2
@deco
def foo(*args):
pass
但是如果装饰器deco
有副作用,那就不一定了。特别是,我原本期待装饰器是没有副作用的,但我遇到了一个有副作用的装饰器,结果让我吃了亏,
#Option1
def bar(*args):
pass
foo = register.filter(bar)
#Option 2
@register.filter
def foo(val, arg):
pass
那么我的期待是错的吗,还是说Django在最佳实践上不一致呢?
2 个回答
0
你的例子在每种情况下表达的意思都不一样!你为什么坚持使用 bar 呢?
看看你的第一个例子:
#Option 1
def bar(*args):
pass
foo = deco(bar)
#Option2
@deco
def foo(*args):
pass
选项 1 是(字面意思上)
foo = deco(bar)
但选项 2 相当于
foo = deco(foo)
你看不出其中的区别吗?
所以,总的来说,是的:你的假设和期望都是错的。
如果你需要函数的原始版本和装饰过的版本,可以提前保存原始版本:
def foo(*args):
pass
bar = foo
foo = deco(foo)
2
其实,这两者是完全一样的:
def foo(*args):
pass
foo = deco(foo)
@deco
def foo(*args):
pass
如果你想给 bar
加上装饰器,并把它叫做 foo
,那么 foo = deco(bar)
是正确的写法。它的意思是:“给这个之前定义的东西 bar
加上装饰,然后叫它 foo
”。装饰器语法的重点在于在定义之前声明这个包装函数,而不是重命名它。
除非你后面还需要用到 bar
,否则没有必要用不同的名字来调用未加装饰的函数。这样做会让你失去使用装饰器语法的便利。
deco
不一定要是一个函数。它也可以是一个有 __call__
方法的对象,这样做的好处是可以很好地封装一些副作用。