为什么Python对静态块的嵌套数量有限制?

72
在Python中,静态嵌套块的数量限制为20。也就是说,嵌套19个for循环是可以的(虽然非常耗时;O(n^19)是无法承受的),但是嵌套20个将会失败并出现以下错误信息:
SyntaxError: too many statically nested blocks

为什么有这样的限制?是否有办法增加限制?


3
为什么你想要增加这个?这对你来说是一个实际问题吗? - Chris_Rands
8
我仍然在思考这在现实生活中的相关性。我会认为只有使用糟糕的编程方式才有可能达到这个限制。或者我错过了什么? - GhostCat
9
两个词:自动生成的代码。 - Federico Poloni
4
@Jason,同样的限制应适用于嵌套的 if。20个嵌套的 if 比20个嵌套的 for 更不刻意。"过度耗时"的论点不适用于它们。 - Federico Poloni
3个回答

84
这个限制不仅适用于 for 循环,还适用于所有其他控制流块。嵌套控制流块的数量限制在 code.h 中定义,使用一个名为 CO_MAXBLOCKS 的常量:
#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */

这个常量用于设置Python执行异常和循环时使用的堆栈最大大小,叫做blockstack。这个限制适用于所有帧对象,并在frameobject.h中显示:
int blockstack[CO_MAXBLOCKS];       /* Walking the 'finally' blocks */

这个限制最有可能是为了在执行嵌套块时保持内存使用在一个合理的水平。这很可能类似于Python对递归调用施加的限制。这个限制可以在compile.c中看到被执行:

if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
    PyErr_SetString(PyExc_SyntaxError,
                    "too many statically nested blocks");
    return 0;
}

关于为什么Python有这个特定的限制,以及为什么他们不能摆脱它,Michael Hudson在2004年的Python邮件列表中给出了更具体的答案:

太准确了。这与Python实现的“块栈”有关,这是Python实现的一个内部细节。我们想摆脱它(不是因为我们想让人们编写超过20个嵌套的for循环的代码 :-) ,但这并不是特别容易(最后:块是最大的问题)。

请注意,在Python 2.6及以下版本中,打破最大嵌套循环数会导致SystemError而不是SyntaxError。然而,这在Python 3中已经改变,并向Python 2.7进行了回溯,以便引发SyntaxError。这在#issue 27514中有所记录:

问题 #27514: 当有太多静态嵌套块时,将其视为SyntaxError而不是SystemError。

这种异常类型的更改原因由Serhiy Storchaka给出:

[...] SystemError并不是应该被引发的异常。SystemError用于在正常情况下无法发生的错误。它只能由错误使用C API或黑客Python内部引起。我认为在这种情况下,SyntaxError更加合适[...]。


3
那么针对这个实际上不存在的问题,解决方案(没有人推荐)是要修改CPython源代码吗? - Chris_Rands
2
@Chris_Rands 是的,我想是这样。如果你改变了CO_MAXBLOCKS然后重新编译,理论上你可以有超过二十个嵌套块。 - Christian Dean
1
@cᴏʟᴅsᴘᴇᴇᴅ 我没有看到过,但测试套件也可能会抱怨 https://github.com/python/cpython/blob/6ea4186de32d65b1f1dc1533b6312b798d300466/Lib/test/test_sys.py#L996 和 https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Lib/test/test_syntax.py#L372 - Chris_Rands
@Chris_Rands,如果我没记错的话,我相信你可以在不进行测试的情况下构建。 - cs95
8
谢谢。写这个答案很有趣。说实话,我从来不知道Python有这个限制。我也学到了新东西。 - Christian Dean

25

这与blockstack有关,它是一个字节码地址的堆栈,用于执行代码块,如循环和异常。

恰好C语言的一个版本(早于C99)将此限制设置为20,由于CPython解释器是使用C构建的,因此遵循了同样的约定

#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */

常数20似乎是根据惯例设置的,除此之外没有其他意义。

[链接来自Christian Dean。]


为什么限制是20?

如果惯例的论点不令人信服,那么看一下 The Zen of Python

In [4]: import this
The Zen of Python, by Tim Peters

...
Flat is better than nested.
...

如何增加这个值?

由于这个值是硬编码常量,改变它影响你的程序的唯一方法是重建你的Python发行版并在新版本上运行你的脚本。

  1. GitHub下载cpython源代码

  2. 进入cpython/Include/code.h文件

  3. CO_MAXBLOCKS的值更改为大于20的任何值

  4. 重新编译Python(禁用测试,否则会有问题



6
你知道吗,C99(我刚才找到的一个标准)允许最多127层嵌套。这比20多一点。而且例如GCC会尽力编译“任何我们拥有资源可以编译的内容”。 - Deduplicator
@Deduplicator 是的,我确实看到这是C99的限制。这更多是一种约定,而不是任何强制性限制,除了内存限制。 - cs95
10
实际上,数字20对我来说有一定的意义,它并不完全是随意选择的:推荐的设置是缩进4个空格,每行限制80个字符。而80/4=20。 - Federico Poloni
1
ANSI C并没有将嵌套限制设置为20。对于“复合语句、迭代控制结构和选择控制结构”,它是15。因此,后来的C标准选择了20级,这个级别更高,并且(正如您已经说明的那样)是相当任意选择的。 - Cody Gray
@CodyGray 谢谢您澄清这一点。我从来没有找到任何官方来源的信息,只是在各种论坛上讨论过。 - cs95

4
请查看答案: too many statically nested blocks python 你无法增加它,因为它是Python语法内置的。这个限制适用于任何类型的代码堆栈(异常、循环等),是设计者的决定(可能是为了保持内存使用合理)。有一件奇怪的事情是,https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Include/code.h#L95 上说20是函数中的最大数量。但我刚刚尝试了在一个函数之外嵌套23个循环,仍然会出现错误。

4
我理解 "在一个函数中" 的意思是,如果你在20层级别上调用另一个函数,那个函数仍然可以嵌套至20层深度。 - Carsten S
哦,这很有道理。 - Cary Shindell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接