実行中のコード内から、非ローカル変数の名前を簡単に取得できますが、 を呼び出してlocals
辞書を取得する方法でそれらの内容を取得するのは少し面倒です。
使用されnonlocal
た変数名は、現在実行中のコード オブジェクトの co_freevars 属性に格納されます。
したがって、非ローカル名を取得するには、次の問題があります。
names = inspect.currentframe().f_code.co_freevars
ただし、これらの変数の内容は、代わりに関数オブジェクト__closure__
の属性 ( func_closure
Python 2 では ) に格納されます。(コード オブジェクトではありません)。問題は、「外部からの支援」がなければ、実行中のコードが実行中の関数オブジェクトに到達する簡単な方法がないことです。コード オブジェクトにリンクするフレーム オブジェクトにアクセスできますが、関数オブジェクトに戻るリンクはありません。(トップレベルで定義された関数の場合、文で使用されているように関数の既知の名前を明示的に使用できますが、呼び出し元に返される囲まれた関数の場合、その名前を知る方法もありません)。def
したがって、トリックに頼る必要があります-gcモジュール(ガベージコレクター)を使用して、現在のコードオブジェクトにリンクするすべてのオブジェクトを取得しますgc.get_referrers
-呼び出しがあります-コードオブジェクトにリンクするすべての関数オブジェクトを返します1つが保持されます。
したがって、非ローカル変数を持つ関数内で次のことができます。
import inspect, gc
from types import FunctionType
def a(b):
b1 = 2
def c():
nonlocal b1
print (b)
code = inspect.currentframe().f_code
names = code.co_freevars
function = [func for func in gc.get_referrers(code) if isinstance(func, FunctionType)][0]
nonlocals = dict (zip(names, (x.cell_contents for x in function.__closure__ )))
print(nonlocals)
return inspect.currentframe()
return c
c = a(5)
f = c()
したがって、非ローカルの名前と値を取得します。ただし、その関数のインスタンスが複数ある場合 (つまり、対象の関数が、それを生成する関数への複数の呼び出しで複数回作成された場合)、これは機能しません。これらのインスタンスはすべて同じコード オブジェクトにリンクします。上記の例では、現在のコードで実行されている関数が 1 つしかないことを前提としています。この場合、正しく動作します。factory 関数をもう一度呼び出すと、別の関数が作成され、非ローカル変数に他の値が含まれる可能性がありますが、同じコード オブジェクトfunction =
が使用されます。上記のリスト ジェネレーターはそれらすべてを取得し、それらの最初のものを任意に選択します。
「正しい」関数は、現在のコードが実行されている関数です。この情報を取得する方法を考えていますが、取得できません。できれば、この回答を完成させますが、今のところ、非ローカル値の値を取得するのに役立ちません。
(非ローカル変数名で「eval」を使用しようとしてもうまくいかないことがわかりました)
非ローカル変数の値が保持されている関数オブジェクトに現在実行中のフレームをリンクする唯一のものは、Python インタープリターのネイティブ側の内部で実行時に作成されるようです。ctypes モジュールを使用して実行時にインタープリターのデータ構造を調べる以外に、それに到達する方法は考えられません。もちろん、実際の製品コードには適していません。
結論: 非ローカル変数名を確実に取得できます。しかし、名前を文字列として指定すると、その値を取得できないようです (再バインドもできません)。
Python のバグ トラッカーまたは Python-ideas メーリング リストで、「非ローカル」呼び出しの機能要求を開いてみることができます。