Почему Python имеет ограничение на количество статических блоков, которые могут быть вложены?


количество статически вложенных блоков в Python ограничено до 20. То есть, вложения 19 for петли будут в порядке (хотя чрезмерно много времени;O(n^19) безумно), но вложенность 20 потерпит неудачу с:

SyntaxError: too many statically nested blocks

какова основная причина наличия такого предела? Есть ли способ увеличить лимит?

3 56

3 ответа:

это ограничение относится не только к for петли, но и для всех других блоков потока управления. Ограничение на количество вложенных блоков потока управления определяется внутри код.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 накладывает на рекурсивные вызовы. Этот предел можно увидеть, что он применяется в компиляции.c:

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

более конкретный ответ о том, почему Python имеет этот специфический предел и почему они не могут избавиться от него, был дан Майкл Хадсон в a 2004 Python список рассылки письмо:

Spot on. Это связано с "блокстаком", очень внутренним подробно о реализации Python. Мы хотели бы избавиться от него (не потому что мы хотим, чтобы люди напишите код с более чем 20 вложенных петли :-) но это не особенно легко (наконец-то: блоки наибольшая проблема.)

обратите внимание, что в Python 2.6 и ниже, нарушая максимальное количество вложенных циклов это бы вызвало SystemError не a SyntaxError. Это было изменено, однако, в Python 3 и обратно исправлено на Python 2.7 так a SyntaxError будет поднят вместо этого. Это было задокументировано в выпуск#27514:

проблема #27514: сделайте слишком много статически вложенных блоков синтаксической ошибкой вместо системной ошибки.

причина этого изменения в типах исключений была указана Сергей Университета :

[...] SystemError не является исключением, которое должно быть вызвано. SystemError - это ошибки, которые не могут возникнуть в обычном случае. Это должно быть вызвано только неправильным использованием C API или взломом внутренних компонентов Python. Я думаю, что SyntaxError более уместен в этом случае [...].

это имеет отношение к blockstack, который представляет собой стек адресов байтового кода и используется для выполнения блоков кода, таких как циклы и исключения.

так получилось, что версия C (старше C99) установила этот предел в 20, и так как интерпретатор CPython построен с помощью C,та же Конвенция была соблюдена:

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

постоянной 20 кажется, что он установлен из конвенции, и ничего больше.

[ссылки любезно Кристиан Дин.]


почему предел 20?

если аргумент конвенции не убедителен, то взгляните на Дзен питона:

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

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

как вы можете увеличить это значение?

поскольку это значение является жестко закодированной константой, единственный способ изменить его в ваших программах-это перестроить дистрибутив python и запустить скрипт в новой сборке.

  1. загрузите исходный код cpython из github

  2. перейти к cpython/Include/code.h

  3. изменить значение CO_MAXBLOCKS к чему-нибудь большему, чем 20

  4. перекомпилировать Python (отключить тесты,они будут жаловаться)

см. ответ здесь: слишком много статически вложенных блоков python Вы не можете увеличить его, поскольку он встроен в синтаксис python. Ограничение применяется к любому виду стека кода (исключения, циклы и т. д.) и это решение дизайнеров (предположительно, чтобы сохранить разумное использование памяти). Одна странная вещь заключается в том, что здесь: https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Include/code.h#L95 он говорит, что 20-это максимальное число в a функция. Но я просто попытался вложить 23 для циклов, а не внутри функции, и вы все равно получите ошибку.