Подтвердить что ты не робот

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

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

SyntaxError: too many statically nested blocks

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

4b9b3361

Ответ 1

Этот предел применяется не только к циклам 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 имеет этот specfic-предел и почему он не может избавиться от него, был предоставлен Майкл Хадсон в списке рассылки Python 2004 года письмо:

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

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

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

Причина этого изменения в типах исключений была дана Serhiy Storchaka:

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

Ответ 2

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

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

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

Константа 20, по-видимому, устанавна, и ничего более.

[Ссылки любезно предоставлены Христианом Дин.]


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

Если аргумент соглашения не убедителен, посмотрите на Zen of Python:

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

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

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

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

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

  • Перейдите к cpython/Include/code.h

  • Измените значение CO_MAXBLOCKS на то, что больше 20

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

Ответ 3

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