【问题标题】:python decorator doesn't take the arguments of the functionpython 装饰器不接受函数的参数
【发布时间】:2021-01-08 18:33:51
【问题描述】:

我正在学习 python,但我被装饰器困住了
我理解的方式是装饰器向函数添加功能
我做了一个简单的函数来检查一个数字是否是偶数
然后是一个装饰器,它添加了绝对值

def decorate(func):
    def is_even_new(*args,**kwargs):
        num = abs(*args,**kwargs)
        func(num)
    return is_even_new()

@decorate 
def is_even(x):
    if x%2 == 0:
        return True
    else:
        return False

is_even(8)

但我不断收到 TypeError:abs() 只接受一个参数(给定 0)
是代码有问题还是我对装饰器的理解是错误的?

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    当你装饰函数时,你应该返回被装饰的函数本身:

    def decorate(func):
        def is_even_new(*args,**kwargs):
            num = abs(*args,**kwargs)
            func(num)
    
        return is_even_new
    

    而不是调用修饰函数并返回:

    def decorate(func):
        def is_even_new(*args,**kwargs):
            num = abs(*args,**kwargs)
            func(num)
    
        return is_even_new()
    

    (注意额外的括号)。在最后一个例子中,当你用@decorate装饰一个函数时,装饰器定义了这个内部函数is_even_new,然后,它不返回后者,而是尝试不带参数地调用它:is_even_new()。这也是为什么你得到 TypeError: abs 期望(确切地)一个论点,但你没有给出它。

    请记住,Python 中的函数与其他任何东西(“一等公民”)一样都是对象,因此您可以直接通过它们的名称来引用它们。

    另外,作为一个建议,如果你知道用@decorate 装饰的函数只会接受一个参数(如is_even),不要使用变量参数和关键字参数,只需定义装饰函数也只取一个参数:

    import functools
    
    
    def decorate(func):
        @functools.wraps(func)
        def decorated(x):
            func(abs(x))
    
        return decorated
    

    这将使错误消息更有帮助(而不是在 abs 调用时提出,

    或者,如果您只想将abs 应用于第一个参数:

    def decorate(func):
        @functools.wraps(func)
        def decorated(x, *args, **kwargs):
            func(abs(x), *args, **kwargs)
    
        return decorated
    

    您还会注意到@functools.wraps。这是一个非常有用的标准库实用程序,用于定义包装函数,例如从装饰器返回的那些。它在包装函数上设置特殊属性,如__name____module__ 等,使其本质上看起来像被包装的函数。

    【讨论】:

      【解决方案2】:

      在您的代码中,您需要以正确的方式从装饰器返回值,并通过牢记其他内部函数的限制来将输入数据更改为装饰器,即(abs 采用 1 个位置参数不多)并且您不能直接从外部完整调用返回函数而不提供return is_new_even() 的值,如果要这样做,您也需要在那里传递参数

      def decorate(func):
          def is_even_new(val):
              num = abs(val)
              return func(num)
          return is_even_new 
      
      @decorate 
      def is_even(x):
          if x%2 == 0:
              return True
          else:
              return False
      
      is_even(8)
      

      【讨论】:

        【解决方案3】:

        我不确定你的装饰函数试图做什么,因为模也适用于负整数,但你基本上有两个问题:

        1. 就像@Anakhand 所说,您应该返回一个函数,而不是函数返回值。
        2. 您的 is_even_new 不会返回任何内容

        所以我猜这是正确的实现:

        def decorate(func):
            def is_even_new(*args,**kwargs):
                num = abs(*args,**kwargs)
                return func(num)
            return is_even_new
        
        @decorate
        def is_even(x):
            if x%2 == 0:
                return True
            else:
                return False
        
        print(is_even(-8))  # --> True
        

        【讨论】:

        • 装饰函数试图获取绝对值,因为原始函数是一个递归函数,它从数字中减去两个(我也试图理解递归)我只是为了澄清而改变了它: "
        猜你喜欢
        • 2015-09-03
        • 1970-01-01
        • 2020-04-02
        • 2015-08-14
        • 2014-07-21
        • 2017-05-26
        • 2015-10-19
        • 1970-01-01
        • 2019-05-13
        相关资源
        最近更新 更多