質問
実行時に入力された Python コードを実行したいので、文字列を取得して呼び出します。
exec(pp, globals(), locals())
どこ pp 文字列です。再帰呼び出しを除いて、正常に動作します。たとえば、次のコードは問題ありません。
def horse():
robot.step()
robot.step()
robot.turn(-1)
robot.step()
while True:
horse()
しかし、これはそうではありません:
def horse():
robot.step()
robot.step()
robot.turn(-1)
robot.step()
horse()
horse()
名前エラー:グローバル名「馬」は定義されていません
再帰的なコードも実行する方法はありますか?
アップデート
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
最上位に置くと機能します。ただし、関数内で移動した場合は次のようになります。
def fn1():
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
fn1()
同じエラーが発生します:名前エラー:グローバル名「rec」が定義されていません
解決
これは、私の作品ます:
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
5
6
7
8
9
10
私が言えることは、おそらくあなたのコードにバグがあるということです。
編集
ここに行く。
def fn1():
glob = {}
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a, glob)
fn1()
他のヒント
これには私も最初は驚きましたが、exec がトップレベルの定義のようにも、外側の関数内の定義のようにも動作しないという、奇妙な特殊なケースのように思えます。何が起こっているのかというと、渡した locals() dict 内で関数定義が実行されているようです。ただし、定義された関数は実際にはこのローカル辞書にアクセスできません。
通常、トップレベルで関数を定義すると、ローカルとグローバルは同じになるため、グローバル内の関数を参照できるため、関数は内部で参照できます。
関数が別の関数のスコープ内で定義されている場合、Python はその関数が関数内でアクセスされていることを認識し、「horse」が外側のスコープのバインディングにマップされるようにクロージャーを作成します。
ここでは、奇妙な中途半端なケースです。exec は定義がトップレベルにあるかのように動作するため、クロージャは作成されません。ただし、ローカルはグローバルと同じではないため、関数がアクセスできる場所には定義されません。アクセスできない外側のローカル dict 内でのみ定義されます。
次のようなことができます。
- ローカルとグローバルの両方に同じ辞書を使用します。つまり「」
exec s in locals(),locals()
" (あるいは、独自の dict を使用することをお勧めします)。globals() dict のみを指定しても同じ効果があります。つまり、「exec s in mydict
" # func を独自の関数の中に入れて、クロージャが作成されるようにします。例えば
s=""" def go(): def factorial(x): if x==0: return 1 return x*factorial(x-1) print factorial(10) go()"""
で提案されているように、「global funcname」ディレクティブを追加することで、関数がローカルではなく globals() に入るように強制します。 ステファンの答え
このは(global rec
を追加しました)私のために動作します。 rec(5)
は地元rec
を呼び出しますが、rec(n+1)
はそれなしで(存在しない)グローバルRECを呼び出します。
def fn1():
a = """global rec
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
「NameError:グローバル名 『REC』は定義されていません」それはグローバルスコープではなく、ローカルスコープでRECを探していることを意味します。それはローカルスコープでRECを定義するが、その後世界的に実行しようとするように見えます。地元の人々()と側でグローバル()あなたが実行している文字列を印刷してみます。