web-dev-qa-db-ja.com

なぜPythonにネストできる静的ブロックの数に制限があるのですか?

Python)の静的にネストされたブロックの数は20に制限されています。つまり、19個のforループをネストすることは問題ありません(時間がかかりすぎますが、O(n^19)非常識ですが)、20をネストすると失敗します:

SyntaxError: too many statically nested blocks

そのような制限がある根本的な理由は何ですか?制限を増やす方法はありますか?

59
Right leg

この制限は、forループだけでなく、他のすべての制御フローブロックにも適用されます。ネストされた制御フローブロックの数の制限は、CO_MAXBLOCKSという名前の定数で code.h 内で定義されます。

#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にこの特定の制限がある理由と、それを取り除くことができない理由に関するより具体的な答えは、 2004年のマイケルハドソンPythonメーリングリストの手紙

スポットオン。これは、Pythonの実装の内部的な詳細である「ブロックスタック」に関係しています。それを取り除きたい(not20を超えるネストされたforループでコードを記述できるようにしたいので:-)最大の問題です)。

Python 2.6以前では、ネストされたループの最大数を壊すと、SystemErrorではなくSyntaxErrorが発生することに注意してください。ただし、これはPython 3で変更され、Python 2.7にバックパッチされるため、代わりにSyntaxErrorが発生します。これは #issue 27514 で文書化されました。

問題#27514:静的にネストされたブロックが多すぎると、SystemErrorではなくSyntaxErrorになります。

例外タイプのこの変更の理由は Serhiy Storchaka によって与えられました:

[...] SystemErrorは発生する例外ではありません。 SystemErrorは、通常のケースでは発生しないエラー用です。 C APIの誤った使用またはPython内部のハッキングによってのみ発生します。この場合、SyntaxErrorの方が適切だと思います[...]。

76
Christian Dean

これは blockstack と関係があり、これはバイトコードアドレスのスタックであり、ループや例外などのコードブロックを実行するために使用されます。

Cのバージョン(C99より古い)がこの制限を20に設定し、CPythonインタープリターはCで構築されているため、 同じ規則に従っています

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

定数20は慣例に従って設定されているようで、それ以上のものはありません。

[リンク提供:クリスチャンディーン。]


なぜ制限は20ですか?

慣習の議論が納得できない場合は、The Zen of Pythonを見てください:

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

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

この値をどのように増やすことができますか?

この値はハードコードされた定数であるため、プログラムで有効に変更する唯一の方法は、pythonディストリビューションを再構築し、新しいビルドでスクリプトを実行することです。

  1. github からcpythonソースコードをダウンロードします。

  2. cpython/Include/code.hに移動します

  3. CO_MAXBLOCKSの値を20より大きい値に変更します

  4. 再コンパイルPython(テストを無効にする、 文句を言う

22
cs95

こちらの回答をご覧ください: too many statically nested blocks python python構文に組み込まれているため、増やすことはできません。制限はあらゆる種類に適用されますコードスタック(例外、ループなど)であり、設計者による決定です(おそらくメモリ使用量を適切に保つためです)。1つの奇妙なことは、ここで: https://github.com/python /cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Include/code.h#L95 関数内の20が最大数であると言いますが、私は関数内ではなくforループの23をネストしようとしましたが、それでもエラーが発生します。

3
Cary Shindell