Python 3中嵌套For循环的最大深度是多少?

What is the maximum depth level of nested For loops in Python 3?

我想知道是否存在这样的"level"。我知道在 C 中限制是 127,但我找不到任何关于 Python 的信息。

例如:

for True:                       # level 0
    for True:                   # level 1
        ...                  
        for True:               # level max
            print("something")

对于 CPython 3.7(和以前的 CPython 版本),限制为 20。但这是实现的一个有点武断的特性; Python 语言定义不需要它,其他 Python 实现(至少 Jython)有不同的限制。见下文。


I know that in C the limit is 127

这不准确。 C 标准建议编译器需要能够处理块嵌套深度至少为 127 的程序,但它不提供任何最大嵌套深度。它确实说:

Implementations should avoid imposing fixed translation limits whenever possible.

事实上,标准并没有说一个实现必须能够处理任何块嵌套为 127 的程序;它说的是,它必须能够处理 "at least one" 这样的程序。 (能够处理任何程序的要求有点高,因为编译器可能会因程序文本的其他问题而窒息。)

Python更不明确。

当然,您可以通过连续尝试更深的嵌套级别来尝试找出极限。使用 bash 脚本(见下文)甚至 python 很容易生成这样的程序。但这并不能抽象地告诉您有关该语言的任何信息。它告诉您的只是您碰巧使用的特定实现中的限制。

您可能会发现相同语言的新版本、相同语言的不同实现,甚至是不同主机上的相同语言的不同限制。

例如,我使用以下 bash 函数生成示例 python 程序:

genpython () { 
    "${2:-python}" -c "$(
          for ((i=0; i<; ++i)); do
            printf "%*sfor i%d in range(1):\n" $i "" $i;
          done;
          printf '%*sprint("Nested %d worked!")\n'  "" ;
        )"
}

生成的程序看起来像(使用 genpython 10):

for i0 in range(1):
 for i1 in range(1):
  for i2 in range(1):
   for i3 in range(1):
    for i4 in range(1):
     for i5 in range(1):
      for i6 in range(1):
       for i7 in range(1):
        for i8 in range(1):
         for i9 in range(1):
          print("Nested 10 worked!")

Python2 (CPython 2.7.15rc1) 和 Python3 (CPython 3.6.7) 均在 20:

$ genpython 20 python2
Nested 20 worked!
$ genpython 21 python2
SyntaxError: too many statically nested blocks

$ genpython 20 python3
Nested 20 worked!
$ genpython 21 python3
SyntaxError: too many statically nested blocks

然而,jython (2.7.1) 能够上升到 99(由于堆栈跟踪而不是简单的语法错误而失败):

$ genpython 99 jython
Nested 99 worked!
$ genpython 100 jython
java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 100
        at org.python.antlr.PythonTokenSource.push(PythonTokenSource.java:323)
        at org.python.antlr.PythonTokenSource.handleIndents(PythonTokenSource.java:288)
        at org.python.antlr.PythonTokenSource.insertImaginaryIndentDedentTokens(PythonTokenSource.java:222)
        at org.python.antlr.PythonTokenSource.nextToken(PythonTokenSource.java:143)
        at org.antlr.runtime.CommonTokenStream.fillBuffer(CommonTokenStream.java:119)
        at org.antlr.runtime.CommonTokenStream.LT(CommonTokenStream.java:238)
        at org.python.antlr.PythonParser.file_input(PythonParser.java:560)
        at org.python.antlr.BaseParser.parseModule(BaseParser.java:77)
        at org.python.core.CompileMode.dispatch(CompileMode.java:22)
        at org.python.core.ParserFacade.parse(ParserFacade.java:158)
        at org.python.core.ParserFacade.parse(ParserFacade.java:203)
        at org.python.core.Py.compile_flags(Py.java:2205)
        at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:267)
        at org.python.util.jython.run(jython.java:394)
        at org.python.util.jython.main(jython.java:142)
java.lang.ArrayIndexOutOfBoundsException: java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 100

出于好奇,我尝试用 C 做同样的事情,使用稍微修改过的脚本:

genc () { 
    { 
        echo '#include <stdio.h>'
        echo 'int main(void) {';
        for ((i=0; i<; ++i)); do
            printf "%*s for (int i%d=0; i%d==0; ++i%d) {\n" $i "" $i $i $i;
        done;
        printf '%*s puts("Nested %d worked!");\n'  "" ;
        for ((i=; i-->0; 1)); do
            printf "%*s }\n" $i "";
        done;
        echo ' return 0;'
        echo '}'
    } | ${2:-gcc} "${@:3}" -std=c11 -x c - && ./a.out
}

这会产生,例如:

#include <stdio.h>
int main(void) {
 for (int i0=0; i0==0; ++i0) {
  for (int i1=0; i1==0; ++i1) {
   for (int i2=0; i2==0; ++i2) {
    puts("Nested 3 worked!");
   }
  }
 }
 return 0;
}

(注意C中的嵌套深度比for语句的嵌套数大1,因为int main() {...}也算。所以上面虽然说它的嵌套深度为3,但实际上是深度4.)

使用 gcc (v8.3.0),我达到了 15000 的嵌套深度。我没有进一步尝试,因为编译时间和内存使用量已经失控。但是 clang (v7.0.0) 更早地产生了一个错误,尽管有一个建议的解决方法:

$ genc 255 clang
Nested 255 worked!
$ genc 256 clang
<stdin>:258:291: fatal error: bracket nesting level exceeded maximum of 256
  ...for (int i255=0; i255==0; ++i255) {
                                       ^
<stdin>:258:291: note: use -fbracket-depth=N to increase maximum nesting level
1 error generated.

使用建议的命令行选项,我能够可靠地达到 3574 的嵌套深度(即 3573 嵌套 for 循环)。但更重要的是,事情开始不一致地失败了。深度 3575 大约有三分之一的尝试失败。深度 3576 大约有一半的时间失败。深度 3577 大约有 80% 的时间失败。失败可能是编译器错误(至少,这是编译器在长堆栈跟踪和更长的错误消息列表之后打印出来的内容)。