【问题标题】:How to Make Python remember a list created inside a function for future use如何让 Python 记住在函数内部创建的列表以供将来使用
【发布时间】:2018-03-09 22:56:23
【问题描述】:

下面是Fibonacci Sequence的迭代计算。

def fibonacci(n):
    if n < 0:
            raise ValueError("invalid index!")
    if n==0:
            return 0
    if n==1:
            return 1

    f = [0,1]
    for i in range(2,n+1):
            f.append(f[i-1] + f[i-2])
    return f[n]

Code Source: brilliant.org

事实上,列表f 是函数内部的一个局部变量,每次调用fibonacci 函数时都会重新创建和重新填充。 如何重写这段代码 sn-p 以便 Python 在调用时无需重新计算 fibonacci(5) 并且可以在下次调用 fibonacci(5) 或更高版本时使用它?我知道全局变量是一种选择,但最“Pythonic”的方式是什么?

【问题讨论】:

  • global 或将可变变量传递给函数。
  • 您可能想检查更好的实施方案:technobeans.com/2012/04/16/5-ways-of-fibonacci-in-python
  • 你应该查一下memoization。这里有一个例子:stackoverflow.com/a/13865482/104349
  • 这有关系吗?我不明白这整个pythonicreligious bs tbh。如果它解决了您的问题并且是可读且或快速的操作,那不是很好吗?无论如何,是的,它是 pythonic -.-
  • @Torxed 全局变量既不是快速的、线程安全的,也不是 Python 的(这仅仅意味着以最直接和前瞻性的思维方式使用该语言,而不是像你习惯的那样语言)。有很多人喜欢修改代码提交,而不考虑可维护性或可靠性,所以无论如何都可以随意这样做;-)

标签: python scope fibonacci memoization


【解决方案1】:

您可以将f 存储在函数范围之外 的变量中。例如:

def memoize_fibonacci():
    f = [0,1]
    def inner_fibonacci(n):
        if n < 0:
                raise ValueError("invalid index!")
        for i in range(len(f),n+1):
                f.append(f[i-1] + f[i-2])
        return f[n]
    return inner_fibonacci

所以每次我们检查f 的长度。如果我们还没有生成请求的索引,我们会生成直到我们获得索引。不管我们是否扩展列表,我们最终都可以返回f[n]

现在我们可以提取fibonacci 函数,使用:

fibonacci = memoize_fibonacci()

如果我们现在对第 200'000 个元素进行两次查询,第二次会更快。

【讨论】:

  • 这实际上比使用 Binet 的公式要快,也有很大的差距(!)
  • 谢谢,@Willem Van Onsem,如果您没有最后一行 fibonacci = memoize_fibonacci 并且只使用 memoize_fibonacci 作为您的函数,会有什么不同吗?在运行时间方面?
  • @Semihcan:是的。因为memoize_fibonacci 不是斐波那契函数。它是斐波那契函数的工厂。
【解决方案2】:

您可以使用闭包来记忆结果:在这种情况下,memo dict 在函数第一次执行时创建(通常是在加载模块时);它是持久的,并在调用函数时填充。

def fibonacci(n, memo={}):
    try: 
        return memo[n]
    except KeyError:
        pass
    if n < 0:
            raise ValueError("fibonacci must be called with positive numbers")
    if n == 0:
        memo[n] = 0 
        return 0
    if n == 1:
        memo[n] = 1
        return 1
    memo[n] = fibonacci(n-1) + fibonacci(n-2)
    return memo[n]

【讨论】:

  • memo dict 是在函数定义执行时创建的(通常是在导入它所在的文件时),而不是在第一次调用函数时创建..
  • 由于它的递归性质,这会在初始调用 fibonacci(1000) 时崩溃,其他解决方案可以处理。记忆对此没有帮助。另外,这在技术上是封闭的吗? IE。谁的变量是memo? (除了增加 Python 的堆栈大小之外,您还可以通过在 fibonacci(1000) 之前调用 fibonacci(900) 来解决这个问题!)
【解决方案3】:

使用python字典并检查键是否存在并从字典中返回结果或在返回之前计算并将结果添加到字典中。

fib_dict = {};

def fibonacci(n):
    if n in fib_dict:
        return fib_dict[n];
    else:
        if n < 0:
            raise ValueError("invalid index!")
        if n==0:
            return 0
        if n==1:
            return 1

        f = [0,1]
        for i in range(2,n+1):
            f.append(f[i-1] + f[i-2])

        fib_dict[n] = f[n];
        return f[n];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 2011-03-08
    • 2016-11-19
    • 1970-01-01
    • 2019-12-10
    • 2020-11-01
    • 1970-01-01
    相关资源
    最近更新 更多