【问题标题】:static variable in a function with Python Decorator使用 Python 装饰器的函数中的静态变量
【发布时间】:2015-08-17 12:56:58
【问题描述】:

我一直在寻找 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 装饰器来处理静态变量。

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

所以我认为它不应该像预期的那样工作,因为decorator(static_var)在每次调用foo时都会初始化foo.counter

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

foo()     
foo()     

但它打印12,增加foo.counter

为什么...?

为什么每次调用 foo 时,foo.counter 不初始化为 0

【问题讨论】:

    标签: python static-variables python-decorators


    【解决方案1】:

    因为:

    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() 逐步完成它

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

    见: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)。

    【讨论】:

      【解决方案2】:

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

      想想什么是静态变量。通常(例如在 C 中)它是函数的局部变量,在对函数的调用中持续存在。这里通过使用恰当地命名为static_var 的装饰器实现了相同的效果,因此每次调用foo() 时,foo.counter 都会递增,而不是重置。

      【讨论】:

        【解决方案3】:

        "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。

        【讨论】:

          猜你喜欢
          • 2023-03-23
          • 1970-01-01
          • 2018-04-07
          • 2013-09-18
          • 2015-11-13
          • 1970-01-01
          • 2017-06-19
          • 1970-01-01
          • 2012-11-24
          相关资源
          最近更新 更多