检查函数是否被调用为装饰器

Tob*_*ann 6 python decorator python-3.x python-decorators

在下面的最小例子decorate中调用了两次.首先使用@decorate,第二个是正常的函数调用decorate(bar).

def decorate(func):
    print(func.__name__)
    return func

@decorate
def bar():
    pass

decorate(bar)
Run Code Online (Sandbox Code Playgroud)

是否可以decorate通过使用@decorate或作为普通函数调用来查看调用是否被调用?

Oli*_*çon 9

@decorator语法是只是语法糖,从而这两个例子中具有相同的行为.这也意味着你们之间所做的任何区别都可能没有你想象的那么有意义.

虽然,您可以使用inspect读取脚本并查看如何在上面的框架中调用装饰器.

import inspect

def decorate(func):
    # See explanation below
    lines = inspect.stack(context=2)[1].code_context
    decorated = any(line.startswith('@') for line in lines)

    print(func.__name__, 'was decorated with "@decorate":', decorated)
    return func
Run Code Online (Sandbox Code Playgroud)

需要注意的是,我们必须指定context=2inspect.stack功能.该context参数表示的围绕当前行的代码有多少行必须归还.在某些特定情况下,例如在装饰子类时,当前行是在类声明而不是装饰器上.这里探讨了这种行为的确切原因.

@decorate
def bar():
    pass

def foo():
    pass
foo = decorate(foo)

@decorate
class MyDict(dict):
    pass
Run Code Online (Sandbox Code Playgroud)

产量

bar was decorated with "@decorate": True
foo was decorated with "@decorate": False
MyDict was decorated with "@decorate": True
Run Code Online (Sandbox Code Playgroud)

警告

还有一些我们难以克服的极端情况,例如装饰器和类声明之间的换行符.

# This will fail
@decorate

class MyDict(dict):
    pass
Run Code Online (Sandbox Code Playgroud)

  • 在给定的代码中永远不会调用@BearBrown`bar`. (2认同)