【问题标题】:staticmethod and recursion?静态方法和递归?
【发布时间】:2012-10-22 10:04:23
【问题描述】:

我有以下代码:

class Foo(object):
    def __init__(self):
        baz=self.bar(10)

    @staticmethod
    def bar(n):
        if n==0:
            return 'bar'
        else:
            return bar(n-1)

bar() 作为递归函数,它需要引用自身。但是,bar() 在一个类中,调用return bar(n-1) 将不起作用,调用NameError: global name 'bar' is not defined。我该如何处理这种情况?我是否应该将 bar() 更改为类或实例方法,允许访问 selfcls

【问题讨论】:

  • 在递归调用中调用Foo.bar(n-1) 有帮助吗?

标签: python class methods


【解决方案1】:

你可以在bar前面加上类名来引用它:

class Foo(object):
    def __init__(self):
        baz=self.bar(10)

    @staticmethod
    def bar(n):
        if n==0:
            return 'bar'
        else:
            return Foo.bar(n-1)

毕竟静态方法只不过是包含在类的命名空间中的常规函数​​。

或者,将bar 定义为常规函数:

def bar(n):
    if n==0:
        return 'bar'
    else:
        return bar(n-1)

class Foo(object):
    def __init__(self):
        baz=bar(10)

这完全避免了整个问题。

【讨论】:

  • @senderle:是的,只是我的一个 c&p 错误。在 Python 3 中也需要它。
  • 实际上,在没有它的情况下,代码在 Python 3 中也能正常运行——至少在从 Foo 本身调用时是这样。 (但我发现从 Foo 实例调用时它不起作用。)
  • @senderle 它在​​ Python 3 中工作,因为没有更多的“未绑定方法”包装器需要 isinstance(self, DefiningClass) 调用方法。仅适用于 @staticmethod 的一件事是调用实例上的方法 (Foo().bar(1))。
  • @senderle:方法的第一个参数是调用 self 只是按照惯例。由于bar 接受名为n 的参数,因此它将被用作实例绑定参数。而且 Python 3 不再强制执行 first-parameter-of-a-class-function-must-be-an-instance 检查,调用 class.method(integer) 可以正常工作。
【解决方案2】:

使用类方法或按名称调用类(如其他人所示)的替代方法是使用闭包来保存对函数的引用:

class Foo(object):
    def bar():
        def bar(n):
            if n == 0:
               return "bar"
            return bar(n-1)
        return bar
    bar = staticmethod(bar())

(次要)优点是,当名称更改时,它不太容易被破坏。例如,如果您有对 Foo.bar inside bar 的引用,这依赖于 Foo 继续作为定义 bar 的类的全局名称。通常这是情况,但如果不是,则递归调用中断。

classmethod 方法将为该方法提供对该类的引用,但该方法中不需要该类,这似乎不优雅。使用闭包也会稍微快一些,因为它不会在每次调用时进行属性查找。

【讨论】:

    【解决方案3】:

    那又怎样?

    class Foo(object):
        def __init__(self):
            baz = self.bar(10)
    
        @classmethod
        def bar(cls, n):
            if n == 0:
                return 'bar'
            else:
                return cls.bar(n-1)
    

    【讨论】:

      【解决方案4】:

      您可以在 Foo 之外定义 bar() ,然后将其作为静态方法引入,这样您就可以获得它作为类方法的所有好处,而不必关闭它或引用类本身。出于类继承的原因,我需要这样的东西。

      def bar(n):
          if n==0:
              return 'bar'
          else:
              return bar(n-1)
      
      class Foo(object):
          bar = staticmethod(bar)
          def __init__(self):
              baz=self.bar(10)
      

      【讨论】:

        【解决方案5】:

        如果主要目标是运行递归方法,您可以为此使用普通方法。

        直到现在我才真正看到它的用途。假设您有需要测试的整数阈值,这种模式可以非常好且容易:(即使它会产生一点过热,所以要小心)

        class Foo(object):
        
            def __init__(self, n):
                self.baz = self.bar(n)
        
            def bar(self, n):
                if n < -10:
                    return 'bar < -10'
                if n == -10:
                    return 'bar -10 - -1'
                if n == 0:
                    return 'bar 0 - 9'
                if n == 10:
                    return 'bar 10 - 19'
                if n >= 20:
                    return 'bar >= 20'
                return self.bar(n-1)
        

        【讨论】:

          猜你喜欢
          • 2014-04-19
          • 2014-01-09
          • 2018-01-08
          • 1970-01-01
          • 2019-08-31
          • 1970-01-01
          • 2020-12-27
          • 1970-01-01
          相关资源
          最近更新 更多