装饰者不应该有副作用?

时间:2009-09-19 07:01:06

标签: python django decorator

编辑,因为初始代码令人困惑。

我认为这两件事情是一样的,

#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 :(得分:2)

实际上,这两者完全相同:

def foo(*args):
    pass
foo = deco(foo)

@deco
def foo(*args):
    pass

如果您要装饰bar并将其称为foofoo = deco(bar)是正确的方法。它说:“装饰这个先前定义的名为bar的东西并称之为foo”。装饰器语法的要点是在定义之前声明包装函数,而不是重命名它。

除非您稍后需要使用bar,否则没有理由使用其他名称调用未修饰的函数。通过这样做,您将完全失去使用装饰器语法糖的能力。

deco不需要是一个函数。它可以是具有__call__方法的对象,这对于封装副作用非常有用。

答案 1 :(得分:0)

在每种情况下,您的示例都不会表达相同的内容!你为什么坚持使用吧?

拿你的第一个例子:

#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)