【问题标题】:When is a function decorated, and when isn't a function decorated?什么时候修饰函数,什么时候不修饰函数?
【发布时间】:2019-09-23 13:31:03
【问题描述】:

我有一个装饰器来记录我的脚本中存在的函数:

registry=[]

def register(func):
    print('running register(%s)' % func)
    registry.append(func)
    return func

然后我有一系列的装饰函数:

@register
def func1():
    print('running f1')

@register 
def func2():
    print('running f2')

这行得通,运行脚本后, print(registry) 返回:

[<function func1 at 0x0000000008433950>, <function func2 at 0x0000000008F06AE8>]

然而单独调用函数,例如:

func1()

只返回'running f1':只是函数,没有修饰。

我期待它返回类似'running register( func1) \n running func1' 的内容。

所以我的问题是,当你有一个装饰函数并调用它时;什么时候单独调用函数,什么时候调用修饰函数?

非常感谢。

【问题讨论】:

    标签: python function decorator


    【解决方案1】:

    您的register(装饰器)函数仅在解释代码时运行一次。

    如果您想更改函数行为,请尝试以下操作:

    def register(func):
        registry.append(func)
        print('adding register(%s)' % func)
    
        def wrap(*args, **kwargs):
            print('running register(%s)' % func)
            return func(*args, **kwargs)
    
        return wrap
    

    第一次打印完成一次,第二次打印在每次调用之前完成。 添加参数将使您的装饰器更加透明。

    【讨论】:

    【解决方案2】:

    我们所说的“装饰器”只是a higher order function@decorator 语法只不过是语法糖,所以这样:

    @decorate
    def func():
        pass
    

    严格等价于

    def func():
        pass
    
    func = decorate(func)
    

    正如 Guillaume Deslandes 所提到的,如果此代码位于模块或脚本的顶层,则装饰器仅在运行时首次加载模块或脚本时调用。

    在您的情况下,装饰器函数 register 返回它的参数(应用它的函数)不变,因此调用“装饰”函数将完全工作,就好像它从未被装饰过一样。

    如果你想以任何方式修改修饰函数(通过在原始函数之前和之后执行代码或其他方式),你必须返回一个 new 函数来“替换”原始函数(但 - 通常 - 保留对原始函数的引用,因此这个新的“包装器”函数仍然可以调用原始函数),这通常是在 using the fact that Python functions are closure:

    def decorate(fun):
       def wrapper(*args, **kw):
           res = fun(*args, **kw)
           print("function {} called with *{}, *{} returned {}".format(fun, args, kw, res)
           return res
    
       return wrapper
    
    
    
    @decorate
    def fun(a):
        return a * 2
    

    【讨论】:

      猜你喜欢
      • 2019-06-28
      • 2014-05-12
      • 1970-01-01
      • 2010-12-28
      • 2021-11-12
      • 2020-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多