【问题标题】:How does a function in Python remember its values after it returns? [duplicate]Python 中的函数在返回后如何记住它的值? [复制]
【发布时间】:2013-04-02 12:58:04
【问题描述】:

警告:极端的新手问题

我似乎一直将函数视为一种配方。在我的世界里,程序是一个食谱盒,一些食谱(功能)调用其他食谱(其他功能)。处理器通过将指令写入 RAM 并处理它们来开始执行主配方。比如早餐薄饼。你叫 Julia Childs 的早餐薄饼食谱。你必须做一次可丽饼面糊。然后,当你还有可丽饼面糊时,你会反复制作可丽饼。同时,您可以制作各种水果制品。

好吧,我显然不明白。我刚刚通过 pythontutor.com 将 python wiki 解决方案运行到 Project Euler Problem 2(斐波那契数的总和小于 400 万)。我认为我发生了一些事情。似乎每次你想出一个食谱时,你不只是使用相同的处理器,你会得到一个带有一些罐子的侏儒来处理那个功能。罐子是变量,gnome 计算出他的配方,如果调用函数期望返回值,则 gnome 将这些罐子的内容显示给调用者。然后调用者可能会返回,找出更多的东西,并向他的调用者显示返回值。

假设 Al 打电话给 Bob 做薄饼。鲍勃做了面糊并叫查理做饭。查理做了一个可丽饼,把可丽饼端给鲍勃,鲍勃把它给了艾尔,然后又回到查理身边。谁还在!艾尔不知道鲍勃把查理藏在厨房里,但即使在查理做了第一个可丽饼之后,他仍然在厨房里,知道如何制作可丽饼,并且知道他还剩下多少可丽饼面糊。即使他已经归还了第一个可丽饼。

有人可以帮我解决这个问题吗?

这是来自 Python wiki 的代码

 def fib():
    x,y = 0,1
    while True:
        yield x
        x,y = y, x+y

def even(seq):
    for number in seq:
        if not number % 2:
            yield number

def under_a_million(seq):
    for number in seq:
        if number > 1000000:
            break
        yield number   

print sum(even(under_a_million(fib())))

这里是http://pythontutor.com/visualize.html

【问题讨论】:

  • 您的困惑是可以理解的。除了yield 关键字之外,程序确实按照您认为应该的方式工作(有点)。 yield,正如您所描述的,在水槽下存储了一个 gnome。在您学习的过程中,您可能会选择避免使用yield,或者您可能会选择专门阅读它。
  • 这里有 generators。每次遇到 yield 关键字时,生成器都会被置于冰上,将控制权交还给在它们上面循环的任何东西。
  • 我必须非常诚实。你极端的烹饪类比让我完全困惑。
  • 你开始与查理和他的可丽饼一起进入有状态的函数,这正在接近面向对象的领域,但在大多数情况下,你的类比是成立的。正如所指出的,yield 和生成器使类比复杂化,因为它们也以有状态的方式起作用。

标签: python


【解决方案1】:

一个简化的答案。

如果您有一个生成一系列值的函数,您可以使用 yield 将其转换为 generator

def func():
    for i in range(3):
        yield i

list(func()) ==> [0,1,2]

for el in func():
    print(el) # 0
              # 1
              # 2

每次调用 yield 时,函数都会在某处冻结。当它再次被调用时,它会从上一个状态继续,并且不会重新开始(除非它已经完成了对元素的消耗)。

如果你调用这个函数,你会得到一个generator,这是你可以迭代的东西。

请注意,这种方式可以迭代无限序列,而无需使用无限内存。

def inf():
    x = -1
    while True:
        x = x + 1
        yield x

for i in inf():
    if i < 10:
        print(i)
    else:
        break

【讨论】:

    【解决方案2】:

    这是因为那些函数不是函数,而是generatorsyield 语句返回一个值,但不从函数返回。每次在生成器上调用next,它都会从上次调用开始继续执行生成器,直到再次到达yield 语句。

    【讨论】:

      【解决方案3】:

      原则上,您的第一个假设是正确的:函数的变量仅在函数执行时可用。但是,在您的情况下,您使用的是 yield 语句。因此,函数调用会返回一个迭代器,该迭代器在被调用时会返回下一个 yield 语句的值。

      查看this post 以进一步了解迭代器是什么以及做什么。

      【讨论】:

        猜你喜欢
        • 2020-06-20
        • 2020-04-27
        • 1970-01-01
        • 2010-09-30
        • 2012-01-08
        • 1970-01-01
        • 2021-04-15
        • 1970-01-01
        • 2020-02-20
        相关资源
        最近更新 更多