Python Decorator函数中的静态变量

时间:2015-06-03 10:51:58

标签: python static-variables python-decorators

我在寻找Python中的静态值。

我找到了this

def static_var(varname, value):
    def decorate(func):
        setattr(func, varname, value)
        return func
    return decorate

@static_var("counter", 0)
def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter

在函数中使用python decorator作为静态变量。

装饰器(static_var)在返回装饰的(foo.counter)函数之前初始化静态值(foo)

所以我认为它不应该按预期工作,因为每次调用(static_var)时,装饰器foo.counter都会初始化foo

因此,我认为如果foo()被调用两次,它应该打印1两次

foo()     
foo()     

但它打印12,增加foo.counter

为什么......?

为什么每次调用foo时foo.counter都没有初始化为0

3 个答案:

答案 0 :(得分:3)

由于:

def static_var(varname, value):
    def decorate(func):
        setattr(func, varname, value)
        return func
    return decorate


@static_var("counter", 0)
def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter

相当于:

foo = static_var("counter", 0)(foo)

请注意static_var()实际上被调用了?现在走过你的装饰师;事实上,用import pdb; pdb.set_trace()

逐步完成
  

装饰者包装其他功能可能会改变它们或   返回新功能或两者兼而有之。

请参阅:Understanding Python Decorators in 12 easy steps

如果我们在你的装饰者身上留下一些print(s),请注意会发生什么:

def static_var(varname, value):
    print "1"

    def decorate(func):
        print "2"
        setattr(func, varname, value)
        return func
    print "3"
    return decorate


@static_var("counter", 0)
def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter


foo()
foo()

输出:

$ python foo.py
1
3
2
Counter is 1
Counter is 2
  

正如我上面所说;首先调用static_var("counter", 0);   然后调用返回(返回函数)   foo因为它是第一个设置初始“计数器”的参数   返回相同的参数(函数foo )。

答案 1 :(得分:2)

“foo.counter每次调用foo时都会初始化为0?”

简答:不,foo.counter仅在调用static_var时设为0。

我想也许你对装饰器和函数装饰器的创建很少感到困惑。

@decorator
def func():
    pass

只是

的语法糖
func = decorator(func)

有了这个,我们就知道您之前的代码等于:

def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter

foo = static_val(foo, "counter", 0)

然后,当您致电foo()时,您正在调用新的foo函数,而不是static_val,其中counter属性将设置为0。

答案 2 :(得分:1)

您看到的行为是正确的。装饰器仅在声明时执行一次,而不是在每次调用装饰函数时执行。因此foo.counter仅初始化为0一次。

想想静态变量是什么。通常(例如在C中)它是函数的局部变量,它在函数调用期间持续存在。通过使用名为static_var的装饰器来实现相同的效果,因此每次调用foo.counterfoo()递增都是有意义的,而不是重置。