この記事では、Python で関数を動的に定義する方法を紹介します。参考になると思います。困っている友人は参考にしてください。お役に立てれば幸いです。
MIT ライセンスに基づく
Python には、実行時の関数定義を簡素化する構文糖はありません。ただし、これは達成が不可能または困難であることを意味するものではありません。
from types import FunctionType foo_code = compile('def foo(): return "bar"', "<string>", "exec") foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo") print(foo_func())
出力:
bar
コードを一行ずつ見てみると、言語/インタープリタの壁がいかに脆弱であるかがわかります。
>>> from types import FunctionType
Python ドキュメントには通常、手動で作成されたクラスを対象としていない機能はリストされていません (これはまったく当然のことです)。この問題を解決するには、help()、inspect (組み込みメソッドは検査できません)、そして最後の解決策である CPython ソース コードを検査するという 3 つの方法があります。 (推奨: python チュートリアル )
この例では、help() と Inspection の両方で作業を完了できますが、実際のソース コードを見ると、データ型の詳細がさらに明らかになります。
>>> from inspect import signature >>> signature(FunctionType) <Signature (code, globals, name=None, argdefs=None, closure=None)>
1. code
は内部的には PyCode オブジェクトであり、types.CodeType として外部に公開されています。非組み込みメソッドには __code__ 属性があり、対応するコード オブジェクトが格納されます。 Types.CodeType オブジェクトは、組み込みのcompile() メソッドを使用して実行時に作成できます。
2. globals
関数がローカルに定義されていない変数を参照するが、パラメータとして渡されるか、デフォルトのパラメータ値によって提供されるか、クロージャ コンテキストを通じて提供される場合、グローバル辞書を検索します。
組み込みの globals() メソッドは、現在のモジュールのグローバル シンボル テーブルへの参照を返すため、現在のテーブルの状態と常に一致する辞書を提供するために使用できます。他の辞書を渡すことも可能です (FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz")。
3. name (オプション)
返された関数の __name__ 属性を制御します。実際に役立つのは、ラムダ (通常は匿名性のため名前がありません) と関数の名前を変更する場合のみです。
4. argdefs (オプション)
任意の型のオブジェクト (def foo(bar="baz" )) を含むタプルを渡すことによって、デフォルトの引数値を指定する方法を提供します。 (FunctionType((lambda bar: bar).__code__, {}, "foo", (10,))() == 10)。
5. クロージャー (オプション)
(CPython 以外の Python VM (PyPy、Jython など) で実行する必要がある場合は、おそらく触れるべきではありません。それは実装の詳細に大きく依存します)。
セル オブジェクトのタプル。セル オブジェクトの作成は、CPython の内部コンポーネントを呼び出す必要があるため、完全に簡単ではありませんが、それを簡単にするライブラリ、exalt (恥知らずな広告) があります。 (注釈: このライブラリは作者によって開発されました。)
>>> foo_code = compile('def foo(): return "bar"', "<string>", "exec")
compile() は組み込みメソッドであるため、十分に文書化されています。
関数の定義には複数のステートメントが必要なため、exec モードが使用されます。
>>> foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")
内容全体を集計し、動的に作成した関数を変数に代入します。
コードの前の文によってコンパイルされた関数は、生成されたコード オブジェクトの最初の定数になるため、foo_code を指すだけでは十分ではありません。生成されたコード オブジェクトには複数の定数を含めることができるため、これは実行モードの直接的な結果です。
>>> print(foo_func())
動的に生成された関数は、他の関数と同様に呼び出すことができます。
最後に
実験を行うことに加えて、動的に作成された関数が必要になるシナリオはほとんどありません。
Python の内部をいじってみることは、Python 言語についてさらに学ぶための素晴らしい方法です。
必要に応じて、通訳者や言語の境界を簡単に越えることができます。
以上がPythonで関数を動的に定義する方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。