web-dev-qa-db-fra.com

Pourquoi Python a-t-il une limite sur le nombre de blocs statiques qui peuvent être imbriqués?

Le nombre de blocs imbriqués statiquement dans Python est limité à 20. C'est-à-dire que l'imbrication de 19 boucles for sera correcte (bien que trop longue; O(n^19) est fou), mais l'imbrication 20 échouera avec:

SyntaxError: too many statically nested blocks

Quelle est la raison sous-jacente d'avoir une telle limite? Existe-t-il un moyen d'augmenter la limite?

59
Right leg

Cette limite s'applique non seulement aux boucles for, mais également à tous les autres blocs de flux de contrôle. La limite du nombre de blocs de flux de contrôle imbriqués est définie à l'intérieur de code.h avec une constante nommée CO_MAXBLOCKS:

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

Cette constante est utilisée pour définir la taille maximale de la pile que Python utilise pour exécuter des exceptions et des boucles nommées blockstack. Cette limite est imposée à tous les objets de cadre et est indiquée dans frameobject.h :

int blockstack[CO_MAXBLOCKS];       /* Walking the 'finally' blocks */

La raison la plus probable de cette limite est de maintenir l'utilisation de la mémoire à un niveau sain lors de l'exécution de blocs imbriqués. C'est probablement similaire à la limite que Python impose aux appels récursifs . Cette limite peut être vue appliquée dans compile.c :

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

Une réponse plus concrète expliquant pourquoi Python a cette limite spécifique et pourquoi ils ne peuvent pas s'en débarrasser, a été donnée par Michael Hudson dans une lettre de liste de diffusion 2004 Python :

Repérez. Cela a à voir avec le "blockstack", un détail interne à l'implémentation de Python. Nous aimerions nous en débarrasser ( pas parce que nous voulons laisser les gens écrire du code avec plus de 20 boucles imbriquées pour les boucles :-) mais ce n'est pas particulièrement facile (enfin: les blocs sont le plus gros problème).

Notez que dans Python 2.6 et inférieur, la rupture du nombre maximum de boucles imbriquées aurait causé un SystemError et non un SyntaxError. Cependant, cela a été changé dans Python 3 et corrigé en arrière à Python 2.7 afin qu'un SyntaxError soit levé à la place. Cela a été documenté dans # problème 27514 :

Problème # 27514: Faites en sorte que trop de blocs imbriqués statiquement soient une SyntaxError au lieu de SystemError.

La raison de ce changement dans les types d'exceptions a été donnée par Serhiy Storchaka :

[...] SystemError n'est pas une exception à lever. SystemError est pour les erreurs qui ne peuvent pas se produire dans le cas normal. Cela ne devrait être causé que par une utilisation incorrecte de l'API C ou par le piratage Python des composants internes. Je pense que SyntaxError est plus approprié dans ce cas [...].

76
Christian Dean

Cela a à voir avec blockstack , qui est une pile des adresses de code octet, et est utilisé pour exécuter des blocs de code tels que des boucles et des exceptions.

Il se trouve qu'une version de C (plus ancienne que C99) avait fixé cette limite à 20, et puisque l'interpréteur CPython est construit avec C, la même convention a été suivie :

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

La constante 20 semble sortir de la convention, et rien de plus.

[Liens avec la permission de Christian Dean.]


Pourquoi la limite est-elle de 20?

Si l'argument de la convention n'est pas convaincant, jetez un œil à Le Zen de Python :

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

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

Comment pouvez-vous augmenter cette valeur?

Comme cette valeur est une constante codée en dur, la seule façon de la modifier pour qu'elle soit appliquée à vos programmes est de reconstruire votre distribution python et d'exécuter votre script sur la nouvelle version.

  1. Téléchargez le code source cpython depuis github

  2. Aller vers cpython/Include/code.h

  3. Modifiez la valeur de CO_MAXBLOCKS à une valeur supérieure à 20

  4. Recompiler Python (désactiver les tests, ils se plaindront )

22
cs95

Voir la réponse ici: trop de blocs python imbriqués statiquement Vous ne pouvez pas l'augmenter car il est intégré à la syntaxe python. La limite s'applique à tout type de pile de code (exceptions , boucles, etc.) et est une décision des concepteurs (probablement pour garder l'utilisation de la mémoire raisonnable). Une chose étrange est qu'ici: https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Include /code.h#L95 il dit que 20 est le nombre maximum dans une fonction . Mais j'ai juste essayé d'imbriquer 23 pour les boucles, pas à l'intérieur d'un fonction, et vous obtenez toujours l'erreur.

3
Cary Shindell