次のpython3コードでエラーが発生するのはなぜですか?
a='''
def x():
print(42)
'''
class Test:
def __init__(self):
exec(a)
x()
t = Test()
このメッセージの結果:
Traceback (most recent call last):
File "bug.py", line 11, in <module>
t = Test()
File "bug.py", line 9, in __init__
x()
NameError: global name 'x' is not defined
注:exec
はPython 2.xの単純なステートメントでしたが、Python 3.xの関数です。
a
を実行して行われた変更を確認しましょう。
_class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec a # NOT a function call but a statement
print locals() == l, globals() == g
x()
t = Test()
_
出力
_False True
42
_
これは、locals
辞書の何かが変更されたことを意味します。 exec
の前後にlocals().keys()
を出力すると、x
の後にexec
が表示されます。 exex のドキュメントによると、
いずれの場合も、オプション部分を省略した場合、コードは現在のスコープで実行されます。
したがって、ドキュメントに記載されているとおりに動作します。
Python 3.xで同じことを実行すると、エラーが発生することを除いて、同様の結果が得られます。
_class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec(a) # Function call, NOT a statement
print(locals() == l, globals() == g)
x()
_
出力
_False True
NameError: name 'x' is not defined
_
exec
関数のドキュメント でさえ、
いずれの場合も、オプション部分を省略した場合、コードは現在のスコープで実行されます。
ただし、下部にメモも含まれています。
注:デフォルトのローカルは、以下の関数
locals()
で説明されているように機能します:デフォルトへの変更ローカル辞書は試行しないでください。関数exec()
が戻った後、ローカルに対するコードの影響を確認する必要がある場合は、明示的なローカル辞書を渡します。
したがって、不思議なことに locals()
ドキュメント をチェックして見つけます
注:この辞書の内容は変更しないでください。変更は、インタプリタが使用するローカル変数と自由変数の値に影響を与えない場合があります。
したがって、インタプリタはlocals()
オブジェクトに加えられた変更を尊重しません。これが、ローカルスコープで定義されているx
を認識しない理由です。
しかし、私たちがするとき
_def __init__(self):
exec(a, globals())
x()
_
globals
ディクショナリに追加するため、機能します。 Pythonは、最初にローカルスコープで、次にクラススコープで、次にグローバルスコープでx
を見つけようとし、そこで見つけます。したがって、問題なく実行されます。
Python2.7ではコードが正常に機能しているため、Python3.xを使用していると想定しています。したがって、Python3.xの場合は、行を変更します
exec(a)
に
exec(a, globals())
x
をグローバル名前空間に追加するため。
Python3 exec
は、マッピングタイプのglobals
およびlocals
オプションの引数も取ります。これらは、指定されたコード実行のコンテキストとして機能します。
_exec(object[, globals[, locals]])
_
デフォルトでは、ローカルスコープは両方に渡されます。実行されたコードはそれを使用でき、dictを変更することもできますが、実際のローカルスコープには影響しません。 locals()
および例を参照してください。
_a = '''
print(t)
def x():
print(42)
'''
class Test:
def __init__(self):
t = 'locals are accessible'
# same as calling exec(a, locals())
exec(a)
print(locals())
x()
t = Test()
_
出力:
_locals are accessible
{'x': <function x at 0x6ffffd09af0>,
'self': <__main__.Test object at 0x6ffffce3f90>,
't': 'locals are accessible'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 13, in __init__
NameError: global name 'x' is not defined
_
x
呼び出しの後にexec
を使用できるようにする場合は、グローバルスコープまたはカスタムスコープを渡す必要があります。
_# global scope
class Test:
def __init__(self):
exec(a, globals())
x()
# custom scope
class Test:
def __init__(self):
scope = {}
exec(a, scope)
scope['x']()
_