65

Python 中的静态嵌套块的数量限制为 20。也就是说,嵌套 19 个for循环就可以了(虽然非常耗时;O(n^19)太疯狂了),但是嵌套 20 个会失败,并出现:

SyntaxError: too many statically nested blocks

有这样一个限制的根本原因是什么?有没有办法提高限额?

4

3 回答 3

80

此限制不仅适用于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;
}

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

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

请注意,在 Python 2.6 及更低版本中,打破嵌套循环的最大数量将导致 aSystemError不是 a SyntaxError。然而,这在 Python 3 中发生了变化,并回溯到 Python 2.7,因此SyntaxError将改为引发 a。这记录在#issue 27514 中

问题 #27514:将过多的静态嵌套块设置为 SyntaxError 而不是 SystemError。

Serhiy Storchaka给出了这种异常类型变化的原因:

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

于 2017-07-07T14:31:09.103 回答
22

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

碰巧有一个 C 版本(早于 C99)将此限制设置为20,并且由于 CPython 解释器是用 C 构建的,因此遵循了相同的约定

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

常数20似乎不合常规,仅此而已。

[链接由克里斯蒂安·迪恩提供。]


为什么限制是20?

如果约定的论点没有说服力,那么看看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(禁用测试,他们会抱怨

于 2017-07-07T14:15:25.170 回答
3

请参阅此处的答案:太多静态嵌套块 python 您无法增加它,因为它内置于 python 语法中。该限制适用于任何类型的代码堆栈(异常、循环等),并且由设计人员决定(大概是为了保持内存使用合理)。一件奇怪的事情是:https ://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Include/code.h#L95它说 20 是函数中的最大数量。但我只是尝试嵌套 23 个 for 循环,而不是在函数内,你仍然会得到错误。

于 2017-07-07T14:11:12.337 回答