3

runpyモジュールを使用してロードされたファイルで定義されたメソッドを実行しようとすると、予期しない動作が発生します。メソッドは、そのメソッドの外部で定義された変数 (インポートされたモジュールを含む) を認識しません。これが私がやっている方法です:

#test.py
import runpy
env = runpy.run_path('test', {'y':'world'})
env['fn']()

#test
import re

print(re.compile(r'^hello', re.IGNORECASE).sub('', "hello world"))
x = "hello"
print(x)
print(y)

def fn():
    try:
        print(re.compile(r'^hello', re.IGNORECASE).sub('', "hello world"))
    except:
        print("No re")
    try:
        print(x)
    except:
        print("No x")
    try:
        print(y)
    except:
        print("No y")

test.py の期待される出力は次のようになります。

 world
hello
world
 world
hello
world

fn は re、x、y のクロージャを形成するためです。

ただし、代わりに次のようになります。

 world
hello
world
No re
None
None

re は、通常のクロージャー動作である必要がありますが、 fn 内で定義されていないようです。x と y は、定義されているように見えますが、None に設定されているため、さらに奇妙です。

これはなぜですか? また、クロージャーは runpy でどのように機能しますか? fn が外部変数を「見る」ことができるような通常の動作を実現するにはどうすればよいですか?

4

1 に答える 1

4

OK、これは Python がモジュールを処理する方法の好奇心です。私はそれについて知っていますが、完全には理解していません。コメントで説明されている IPython の作業中に遭遇しました。

Python がモジュールを実行すると、モジュール オブジェクトが生成されます。このオブジェクトの属性は、モジュール内のグローバル名です。モジュールがスコープから外れて破棄されると、これらの属性は に設定されNoneます。関数で定義されたコードは、これらをグローバルとして認識します。def g(): return globals()これは、ファイルに追加してから呼び出すことで実証できますenv["g"]()

でこれを回避する方法があるかどうかはわかりませんrunpy。IPython は、いくつかの複雑なコードを使用して、他のファイルを実行するためにモジュール オブジェクトを再利用し、そのコピーをキャッシュして__dict__その中の参照を維持します。magic_run気になる機能があれば調べてみてください。

于 2011-08-17T12:25:55.163 に答える