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

时间:2017-07-07 14:00:04

标签: python nested-loops language-implementation

Python中静态嵌套块的数量限制为20个。 也就是说,嵌套19 for循环会很好(虽然过于耗时; O(n^19)是疯了),但嵌套20将失败:

SyntaxError: too many statically nested blocks

有这样限制的根本原因是什么? 有没有办法增加限额?

3 个答案:

答案 0 :(得分:73)

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

此限制的最可能原因是在执行嵌套块时将内存使用保持在理智水平。它可能与the limit Python imposes on recursive calls相似。可以看到此限制在compile.c中强制执行:

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

Michael Hudson in a 2004 Python mailing list letter给出了一个更为具体的答案:为什么Python有这个特定的限制以及为什么它们无法摆脱它?

  

点亮。这与' blockstack'非常相关   详细介绍了Python的实现。我们想摆脱它(不是   因为我们想让人们编写超过20个嵌套的代码   循环:-)但它不是特别容易(最后:块是   最大的问题)。

请注意,在Python 2.6及更低版本中,打破嵌套循环的最大数量会导致SystemError而不是SyntaxError。然而,在Python 3中对此进行了更改,并将其修补为Python 2.7,因此将引发SyntaxError。这在#issue 27514

中有记录
  

问题#27514:使有太多静态嵌套的块成为SyntaxError     而不是SystemError。

异常类型更改的原因由Serhiy Storchaka

提供
  

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

答案 1 :(得分:21)

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

恰好有一个版本的C(早于C99)将此限制设置为20,并且由于CPython解释器是使用C构建的,the same convention has been followed

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

常量20似乎是在惯例之外设置的,仅此而已。

[链接由Christian Dean提供。]

为什么限制为20?

如果约定的论点不具说服力,那么看一下 Python的禅宗

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

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

如何增加这个值?

由于此值是一个硬编码常量,因此将其更改为在程序中生效的唯一方法是重建python发行版并在新版本上运行脚本。

  1. github

  2. 下载cpython源代码
  3. 导航至cpython/Include/code.h

  4. CO_MAXBLOCKS的值更改为大于20的

  5. 重新编译Python(禁用测试,they'll complain

答案 2 :(得分:3)

请在此处查看答案:too many statically nested blocks python 你不能增加它,因为它内置于python语法。该限制适用于任何类型的代码堆栈(异常,循环等),并且是设计者的决定(可能是为了保持内存使用的合理性)。 一个奇怪的事情是:https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Include/code.h#L95它表示20是函数中的最大数字。但我只是尝试嵌套23 for循环,而不是在函数内部,你仍然得到错误。