【问题标题】:How to retrieve arguments from a "fluid" decorated function如何从“流体”装饰函数中检索参数
【发布时间】:2016-06-02 06:28:25
【问题描述】:

假设我有这个装饰器:

def decorator(f):
  def f_wrap(*args):
    for item in args:
      print(args)
    return f(*args)
  return f_wrap

当使用@ 语法作为“永久”装饰器时,args 检索包装函数的参数。例如,当与下面的类一起使用时,我收到MyObject 的实例。

Class MyObject(object):
  def __init__(self):
    pass

  @decorator
  def function(self):
    return

如何使用“流体”装饰器实现相同的结果。或者不是永久绑定到它正在装饰的功能的装饰器?例如:

def decorator(f):
    def f_wrap(*args):
        if (not args):
            print("Nothing in args")
        return f(*args)
    return f_wrap

class MyClass(object):
    def __init__(self):
        pass

    def function(self):
        return

if __name__ == "__main__":
    myobj = MyClass()
    myobj.function = decorator(myobj.function)
    myobj.function()

在这种情况下,args 元组总是返回空(我总是得到“Nothing in args”),尽管我预计它会返回实例变量 myobj

编辑

如果从@AChampion 的帖子中不清楚,解决方案是简单地将流体装饰方法称为“未绑定”方法。例如,

from types import MethodType
def decorator(f):
    def f_wrap(*args):
        # I replaced this with an iteration through
        #   args. It's a bit more demonstrative.
        for item in args:
            print(item)
        return f(*args)
    return f_wrap

class MyClass(object):
    def __init__(self):
        pass

    def function(self):
        return

if __name__ == "__main__":
    myobj = MyClass()
    myobj.function = MethodType(decorator(MyClass.function), myobj)
    myobj.function()

【问题讨论】:

  • 你确定你的条件是正确的all(args) 将返回 False 与任何不可证伪的参数,例如0.你只是想要args的len吗?造成差异的原因是第二个实例有一个bound 函数(打印出f),而第一个实例只是传入了一个未绑定的函数。

标签: python python-decorators


【解决方案1】:

您没有正确使用allall 返回一个布尔值,用于判断您在 all 中检查的内容是否满足所有条件。在你的情况下,你并没有真正做任何事情。您将始终根据您使用all 的方式评估为True。

我相信您正在寻找的只是这个:

if not args:

现在,最终检查的是您正在执行的方法是否有 *args。对于您拥有的函数,您没有传递任何参数,因此,使用if not args 检查,您实际上会得到:

"Nothing in args"

但是,如果您将参数添加到您的方法中:

def function(self, x):
    return

然后拨打:myobj.function(1)

您将不会得到“args 中的任何内容”。

回答您关于未获取实例的最后一个问题。如果您使用这种调用装饰器的方法打印出f

myobj.function = decorator(myobj.function)
myobj.function()

你会得到一个绑定的方法:

<bound method MyClass.function of <__main__.MyClass object at 0x102002390>>

现在,像这样设置你的装饰器:

@decorator
def function(self):
    return

你会看到你的类对象附加了一个函数:

<function MyClass.function at 0x102001620>

因此表明他们没有做你所期望的完全相同的事情。希望这有助于澄清一点。

【讨论】:

  • 问题仍然存在:为什么我没有得到实例变量?使用“永久”装饰器,即使没有传递任何参数,我也会得到实例。例如,程序返回:&lt;__main__.MyClass object at [address]&gt;.
  • @franklin 已更新。让我知道这是否有帮助。
  • 区别在于封装绑定方法和非绑定方法
  • @idjaw 完全正确。但是,它仍然使用我试图避免的永久装饰器。这绝对是一个涉及绑定和非绑定方法的问题(我承认需要阅读)。谢谢!
【解决方案2】:

差异的原因是你包装了不同的东西,一个未绑定的方法与一个绑定的方法:

class MyObject(object):
    @decorator
    def function(self):
         pass

相当于:

import types
class MyClass(object):
    def function(self):
        pass

m = MyClass(object)
m.function = types.MethodType(decorator(MyClass.function), m)

不是:

m.function = decorator(m.function)

第一个是未绑定的方法,第二个是绑定的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-14
    • 2013-02-24
    • 2021-11-21
    • 2019-07-29
    • 2018-01-21
    • 2011-09-22
    • 2018-09-09
    • 2021-11-18
    相关资源
    最近更新 更多