【问题标题】:How can I see if a method is a decorator?如何查看方法是否是装饰器?
【发布时间】:2012-04-05 09:53:16
【问题描述】:

是否可以检查函数/方法以查看它是否可以用作装饰器?因为它遵循装饰器包装其他函数并返回可调用的通常方式?具体来说,我希望验证第 3 方代码。

【问题讨论】:

  • 你的意思是可以用作装饰器还是在某处用作装饰器?虽然第一个可能证明非常困难,如果不是不可能普遍解决,第二个实际上可能是可行的。
  • 或者你是在问函数是否被修饰过?
  • @NiklasB。抱歉 - 澄清了问题。
  • @unpluggd:目前看来这是一项不可能完成的任务,如果您告诉我们您为什么需要它,也许我们可以更好地帮助您。

标签: python decorator introspection


【解决方案1】:

任何具有正确数量参数的可调用对象都可以用作装饰器。请记住

@foo
def bar(...):

一模一样和

def bar(...):
   ...
bar = foo(bar)

当然,由于foo 可以返回任何东西,因此您无法检查函数是否已被修饰。虽然foo 可以很好并留下标记,但它没有义务这样做。


如果给你一些 Python 代码并且你想找到所有装饰器,你可以通过将代码解析成抽象语法树然后遍历树来寻找装饰函数来做到这一点。这是一个示例,存储了装饰器的.ids。显然,如果您愿意,可以存储 astobjects。

>>> class DecoratorFinder(ast.NodeVisitor):
...     def __init__(self, *args, **kwargs):
...         super(DecoratorFinder, self).__init__(*args, **kwargs)
...         self.decorators = set()
...     
...     def visit_FunctionDef(self, node):
...         self.decorators.update(dec.id for dec in node.decorator_list)
...         self.generic_visit(node)
... 
>>> finder = DecoratorFinder()
>>> x = ast.parse("""
... @dec
... def foo():
...     pass
... """)
>>> finder.visit(x)
>>> finder.decorators
set(['dec'])

【讨论】:

  • 实际上只有至少有一个位置参数的可调用对象是可能的......
【解决方案2】:

不,这是不可能的。可能不是检查f 是否是装饰器,而是应该考虑为什么需要检查它?

如果你期待一些特定的装饰器,你可以直接检查,如果你想要一些特定的行为/方法/属性,你可以检查

如果您想检查一些可调用的f 是否可以用作装饰器,您可以通过传递一些虚拟函数来测试装饰器的行为,但通常它可能不起作用或对于不同的输入有不同的行为。

这是一个如此幼稚的检查:

def decorator1(func):
    def _wrapper(*args, **kwargs):
        print "before"
        func(*args, **kwargs)
        print "after"

    return _wrapper

def dummy_func(): pass

out_func = decorator1(dummy_func)

if callable(out_func) and dummy_func != out_func:
    print "aha decorated!"

【讨论】:

  • you can check that directly by passing some dummy function??不是真的......你无法告诉 它将如何处理它的论点!
  • @katrielalex 是的,为什么一般答案是否定的,但是如果您知道装饰器应该做什么,您可以使用它来检查行为
【解决方案3】:

通过应用可疑的装饰器,捕获异常,然后测试结果是否包含__call__ 方法,您可以猜测给定的可调用对象是否是装饰器。但这只是猜测,不是保证。

除此之外,由于 Python 语言的动态类型特性以及 CPython 解释器中内置函数的特殊处理,我不相信您想要的一般情况下是可能的。无法以编程方式判断一个可调用对象是否会接受另一个可调用对象作为参数,或者它的返回值将具有什么类型。此外,在 CPython 中,对于用 C 实现的函数,您甚至无法检查可调用对象以查看它接受了多少参数。

“装饰者”这个词可以用来表示不同的东西。定义它的一种方法是,装饰器是接受单个(可调用)参数并返回可调用对象的任何可调用对象。

请注意,在这个定义中我什至没有使用“函数”这个词;这样做实际上是不正确的。确实,一些常用的装饰器具有奇怪的属性:

  • 内置的 classmethod 和 staticmethod 装饰器返回描述符对象,而不是函数。
  • 自语言版本 2.6 起,您可以装饰类,而不仅仅是函数和方法。
  • 任何包含__init__(self, somecallable) 方法和__call__(self, *args, **kwargs) 方法的类都可以用作装饰器。

【讨论】:

  • 谢谢 - 您关于装饰器可以是“[a] callable 接受单个可调用参数并返回可调用”的声明将是我测试的基础,应该足以验证,因为这就是它们应该在第 3 方代码中创建。但是,从复杂性来看,我将尝试提供一些不错的错误消息。 :D
【解决方案4】:

由于 Python 中没有标准化的装饰器,因此没有真正的方法来判断一个函数是否是一个装饰器,除非您对正在寻找的装饰器有所了解。

如果装饰器在你的控制之下,你可以添加一个标记来表明它是一个装饰函数。否则就没有真正统一的方式来做到这一点。举个例子:

def decorator(func):
    return g

@decorator
def f()
    pass

def g():
    pass

在上面的例子中,在运行时,f 和 g 将是相同的,没有办法区分这两者。

【讨论】:

    【解决方案5】:

    我从来没有做过这样的事情,但一般来说,python 在这种情况下依赖于“duck-typing”。因此,您可以尝试装饰一个虚拟函数并查看是否返回了可调用对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-12
      • 2016-12-14
      • 2011-07-26
      • 2011-05-30
      • 2019-11-27
      • 2013-10-19
      • 1970-01-01
      • 2017-02-04
      相关资源
      最近更新 更多