Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 用生成器定义“fac”。还有:为什么发电机没有堆栈溢出?_Python - Fatal编程技术网

Python 用生成器定义“fac”。还有:为什么发电机没有堆栈溢出?

Python 用生成器定义“fac”。还有:为什么发电机没有堆栈溢出?,python,Python,有没有办法通过Python中的生成器定义以下代码(递归的经典示例)?我正在使用Python3 def fac(n): 如果n==0: 返回1 其他: 返回n*fac(n-1) 我试过了,没有成功: [1]中的:定义fib(n): …:如果n==0: …:收益率1 …:其他: …:n*产量(n-1) 文件“”,第5行 n*产量(n-1) ^ SyntaxError:无效语法 Python中的经典递归导致堆栈溢出 这个经典示例导致我的机器上的堆栈溢出,输入值为n=3000。在Lisp方言“Sch

有没有办法通过Python中的生成器定义以下代码(递归的经典示例)?我正在使用Python3

def fac(n):
如果n==0:
返回1
其他:
返回n*fac(n-1)
我试过了,没有成功:

[1]中的
:定义fib(n):
…:如果n==0:
…:收益率1
…:其他:
…:n*产量(n-1)
文件“”,第5行
n*产量(n-1)
^
SyntaxError:无效语法
Python中的经典递归导致堆栈溢出 这个经典示例导致我的机器上的堆栈溢出,输入值为
n=3000
。在Lisp方言“Scheme”中,我将使用尾部递归并避免堆栈溢出。在Python中不可能。这就是为什么生成器在Python中派上用场的原因。但我想知道:

为什么发电机没有堆栈溢出? 为什么Python中的生成器没有堆栈溢出?他们如何在内部工作?做了一些研究之后,我总是会看到一些示例,展示如何在Python中使用生成器,但并没有太多关于内部工作的内容

更新1:
从my_函数中获得收益(…)
正如我试图在评论中解释的那样,也许我上面的例子是一个错误的选择。我的实际问题是针对Python 3中
yield from
语句中递归使用的生成器的内部工作

下面是我用来处理Firebox书签备份生成的JSON文件的(不完整)示例代码。在某些情况下,我使用
yield from process_json(…)
通过生成器再次递归调用函数

在本例中,如何避免堆栈溢出?还是这样


#(剪报)
文件夹和书签={}
文件夹\u日期={}
def process_json(json_输入,文件夹_路径=”):
全局文件夹\u和\u书签
#使用生成器处理json
#(为了避免递归,请使用生成器)
# https://stackoverflow.com/a/39016088/5115219
#node是dict吗?
如果isinstance(json_输入,dict):
#我们有一个口述
guid=json_输入['guid']
title=json_输入['title']
idx=json_输入['index']
date_added=到_datetime_applescript(json_输入['dateAdded'])
last_modified=to_datetime_applescript(json_输入['lastModified'])
#我们有容器还是书签?
#
#字典里有“uri”吗?
#如果没有,我们有一个容器
如果json_input.keys()中的“uri”:
uri=json_输入['uri']
#返回带有文件夹或容器的URL(=上一个标题)
#书签=[guid、标题、idx、uri、添加日期、上次修改]
书签={'title':标题,
'uri':uri,
“添加日期”:添加日期,
“上次修改”:上次修改}
文件夹和书签[文件夹路径].附加(书签)
收益书签
json_input.keys()中的elif“children”:
#所以我们有一个容器(又名文件夹)。
#
#创建一个新文件夹
如果标题!=“”:#我们不是根
文件夹路径=f“{folder\u path}/{title}”
如果文件夹和书签中的文件夹路径为:
通过
其他:
文件夹和书签[文件夹路径]=[]
文件夹日期[文件夹路径]={'date'u added':date'u added','last'u modified':last'u modified}
#在子进程列表上运行进程\u json
#json_输入['children']:目录列表
从进程生成json(json输入['children'],文件夹路径)
#或者节点是一个目录列表?
elif isinstance(json_输入,列表):
#处理容器的子级。
dict_list=json_输入
对于dict_列表中的d:
来自进程\u json(d,文件夹\u路径)的产量
更新2:
yield
vs
yield from
好的,我明白了。感谢所有的评论

  • 因此,通过
    生成的生成器将生成
    迭代器。这与递归无关,因此这里没有堆栈溢出
  • 但是,通过
    从my_函数(…)
    生成的生成器实际上是我函数的递归调用,尽管有延迟,并且只有在需要时才进行计算

第二个示例确实会导致堆栈溢出

好的,在你的评论之后,我已经完全重写了我的答案

  • 递归是如何工作的,为什么会出现堆栈溢出
  • 递归通常是解决问题的一种优雅方式。在大多数编程语言中,每次调用函数时,函数所需的所有信息和状态都会放在堆栈上,即所谓的“堆栈帧”。堆栈是一个特殊的每线程内存区域,大小有限

    现在递归函数隐式地使用这些堆栈帧来存储状态/中间结果。例如,阶乘函数是n*(n-1)*((n-1)-1)。。。1和所有这些“n-1”都存储在堆栈上

    迭代解决方案必须将这些中间结果显式存储在变量中(通常位于单个堆栈框架中)

  • 生成器如何避免堆栈溢出
  • 简单地说:它们不是递归的。它们像迭代器对象一样实现。它们存储计算的当前状态,并在每次请求时返回一个新结果(隐式或使用next()

    如果它看起来是递归的,那只是语法上的甜点。“收益率”与回报率不同。它生成当前值,然后“暂停”计算。这一切都被包裹在一个对象中,而不是在无数的堆栈帧中

    这将给你一个从1到n的系列!':

    def fac(n):
        if (n <= 0):
            yield 1
        else:
            v = 1
            for i in range(1, n+1):
                v = v * i
                yield v
    
    这看起来是递归的,但它是两个生成器对象的组合。您拥有“内部”生成器(仅使用一个对象的空间),使用
    yield from
    您可以说“我想将该生成器中的所有值转发给我的调用者”

    所以
    def process_json(json_input, folder_path=""):
        # Some code
        yield from process_json(json_input['children'], folder_path)