【问题标题】:Printing out the fibonacci series打印出斐波那契数列
【发布时间】:2015-01-04 08:39:03
【问题描述】:

我正在尝试编写一个简单的 Python 程序。它应该返回一个返回连续斐波那契数的闭包:

def fibGen():
    n_1 = 0
    n_2 = 0 
    n = 1
    def fib():
        if n_1 ==0 and n_2 ==0:
            n_1 = 1
            return n
        else:
            n = n_1 + n_2
            n_2 = n_1
            n_1 = n  
            return n
    return fib

f = fibGen()
for i in range(0,10):
    print(f())

我在运行时收到此错误: UnboundLocalError: local variable 'n_1' referenced before assignment

编辑:在我原来的帖子中,我没有在fibGen 的定义中包含n = 1,但这实际上是一个错字。无论如何,我仍然会遇到同样的错误。

【问题讨论】:

    标签: python python-3.x closures fibonacci


    【解决方案1】:

    Python 在编译时根据绑定行为确定变量的范围。如果您分配给一个名称,或者将其用作import 目标(以及其他一些方式),那么您就是将该名称绑定到一个范围内。

    您在fib() 函数中绑定到n_1n_2;两者都被分配到。这使得这两个名称在fib()本地,Python 甚至不会查看周围的范围。

    您需要覆盖此行为,您可以使用nonlocal statement

    def fibGen():
        n_1 = 0
        n_2 = 0 
        def fib():
            nonlocal n_1, n_2
            if n_1 ==0 and n_2 ==0:
                n_1 = 1
                return n
            else:
                n = n_1 + n_2
                n_2 = n_1
                n_1 = n  
                return n
        return fib
    

    nonlocal 告诉编译器明确您不希望它查看绑定行为,而是将名称视为闭包。

    接下来,您在if 测试的第一个分支中使用n,但您还没有在else 分支之外的任何地方定义它。无论如何,你应该返回1

    def fibGen():
        n_1 = 0
        n_2 = 0 
        def fib():
            nonlocal n_1, n_2
            if n_1 ==0 and n_2 ==0:
                n_1 = 1
                return n_1
            else:
                n = n_1 + n_2
                n_2 = n_1
                n_1 = n  
                return n
        return fib
    

    最后但同样重要的是,您可以使用元组赋值来交换两个变量,无需中介:

    def fibGen():
        n_1 = 0
        n_2 = 0 
        def fib():
            nonlocal n_1, n_2
            if n_1 ==0 and n_2 ==0:
                n_1 = 1
            else:
                n_1, n_2 = n_1 + n_2, n_1
            return n_1
        return fib
    

    【讨论】:

      【解决方案2】:

      您不能修改封闭变量,n_1、n_2 位于enclosing 空间而不是函数空间,这就是您无法更改变量的原因。

      使用nonlocal关键字

      def fibGen():
          n_1 = 0
          n_2 = 0 
          def fib():
              nonlocal n_1, n_2
              if n_1 ==0 and n_2 ==0:
                  n_1 = 1
                  return n_1 # return `n_1` here not `n`
              else:
                  n = n_1 + n_2
                  n_2 = n_1
                  n_1 = n  
                  return n
          return fib
      
      f = fibGen()
      for i in range(0,10):
          print(f())
      

      【讨论】:

      • @novice66 但我的回答很好地解释了您的代码中的问题。
      • 我知道,这就是为什么我“赞成”它以取消您从其他人那里得到的反对票。
      • 有趣的是,现在可以发布这样的答案,而无需提及它是 py3 功能。也许我们终于过了 py2->py3 的临界点。此外,+1 是因为您看起来比接受的答案早 1 分钟,但该答案使用您的相同功能、可变名称等。
      • @PhilCooper 谢谢。
      【解决方案3】:

      我一直在审查其中一些众所周知的算法,并认为我会在 Python 中使用闭包来分享我的斐波那契版本:

      #!/usr/bin/env python
      
      def fibonacci():
          a = 0
          b = 1
      
          def internal_fibonacci():
              nonlocal a, b
              a, b = b, a+b
              return a
          return internal_fibonacci
      
      
      def main():
          f = fibonacci()
          for i in range(0,10):
              print("f(" + str(i) + ") => " + str(f()))
      
      
      if __name__ == '__main__':
          main()
      

      比这里提供的其他解决方案更优雅。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 2022-11-27
        • 1970-01-01
        • 2020-03-05
        相关资源
        最近更新 更多