【问题标题】:Decorator error: NoneType object is not callable装饰器错误:NoneType 对象不可调用
【发布时间】:2013-01-10 06:27:22
【问题描述】:

我写了一个这样的函数装饰器:

def tsfunc(func):
    def wrappedFunc():
        print '%s() called' % func.__name__
        return func()
    return wrappedFunc()

@tsfunc
def foo():
    pass

foo()  # to get it work, use foo instead of foo()
foo()

我收到以下错误消息:

foo() called
Traceback (most recent call last):
  File "decorator.py", line 11, in <module>
    foo()
TypeError: 'NoneType' object is not callable

我通过将“foo()”替换为“foo”来实现它。但我还是没有得到我期望的结果:

foo() called

好像foo 函数只被调用一次。

请帮助我理解为什么会这样。

【问题讨论】:

    标签: python python-2.7 decorator python-decorators


    【解决方案1】:

    你应该返回包装函数本身,而不是它的结果

    def tsfunc(func):
        def wrappedFunc():
            print '%s() called' % func.__name__
            return func()
        return wrappedFunc   # Do not call the function, return a reference instead
    

    装饰器用装饰器的返回值替换被装饰的项目:

    @tsfunc
    def foo():
        # ....
    

    相当于:

    def foo():
        # ....
    foo = tsfunc(foo)
    

    扩展为(在您的代码中):

    foo = wrappedFunc()
    

    所以您将函数 foo 替换为 wrappedFunc() 调用的结果,而不是 wrappedFunc 本身。

    【讨论】:

      【解决方案2】:

      你需要去掉括号

      return wrappedFunc
      

      装饰器应该返回包装函数,而不是调用它。

      通过此修复,代码生成:

      foo() called
      foo() called
      

      【讨论】:

        【解决方案3】:

        有点晚了,但希望这会有所帮助,扩展所提供的答案被接受的原因

        如错误所述,“NoneType”表示我们尝试调用的实例/对象没有类型(它不是函数/int/boolean/class/instance)。它的类型只是“无” 总而言之,装饰器只不过是对闭包的扩展使用,其函数被视为一等公民(您可以在closures 上获得详细视图 这基本上意味着装饰器希望返回一个函数,例如在大多数情况下是一个包​​装器,原始函数保持不变并与装饰器一起调用

        def tsfunc(func):
            def wrappedFunc():
                print '%s() called' % func.__name__
                return func()
            return wrappedFunc() -> Here the function is not returned but called eventually
        
        @tsfunc
        def foo():
            pass
        
        foo() - > calling this again doesnt make sense to trigger the decorator, since a reference for the method foo is enough. Hence foo works fine but foo() doesn't (method call has completed already but no value is returned) If you try like this, you would see that the variable has 'None' type
        
        def tsfunc(func):
                def wrappedFunc():
                    print '%s() called' % func.__name__
                    return func()
                return wrappedFunc --  Here I made the correction
            
            @tsfunc
            def foo():
                pass
        var1 = foo()
        print(var1)
        

        当您以不正确的方式调用包装函数而不是仅返回函数时,调用 foo() 会发生这种情况

        因此,要使装饰器按照规范运行,它应该返回一个包装函数,而原始函数保持不变。因此应该根据接受的答案重写它

        【讨论】:

          【解决方案4】:

          你使用这个语法

          def tsfunc(func):
              def wrappedFunc():
                  print '%s() called' % func.__name__
                  return func()
              return wrappedFunc # not use wrappedFunc() becaues Because this function runs at the this time 
          
          @tsfunc
          def foo():
              pass
          
          foo()  # 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-03
            • 2020-08-19
            • 2021-11-22
            • 2019-03-17
            • 2020-09-22
            • 1970-01-01
            • 2019-11-18
            相关资源
            最近更新 更多