2009-05-16 28 views
5

とのexec()を使用して、私は、実行時に入力されたいくつかのPythonコードを実行したいので、私は文字列を取得し、は文字列です再帰関数

exec(pp, globals(), locals())

を呼び出します。再帰呼び出しを除いて正常に動作します。 。

def horse(): 
    robot.step() 
    robot.step() 
    robot.turn(-1) 
    robot.step() 

while True: 
    horse() 

しかし、これではありません::gが、例えば、このコードはOKです

def horse(): 
    robot.step() 
    robot.step() 
    robot.turn(-1) 
    robot.step() 
    horse() 

horse() 

NameError: global name 'horse' is not defined

も同様に再帰的なコードを実行する方法はありますか?

UPDATE

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() 

同じエラーが発生します。NameError:グローバル名「REC」が

+0

により示唆されるように、「グローバルfuncnameに」ディレクティブを入れることで地元の人々は、このexecの文字列は、ユーザからのものではない教えてください入力。 –

+0

@Nadiaなぜ、はい、それは_is_ :) – Headcrab

答えて

4

が定義されていないそれは私の作品:

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() 
+0

まあ、正確には - 上の更新を参照してください... – Headcrab

+0

どうしてですか? – Headcrab

+0

@Headcrab、それはあなたに編集可能なグローバルと地方の辞書を与えるので。 locals()は "本当の"ローカル変数を変更できない辞書を提供します。 – Unknown

0

が行く

編集ここ

"NameError:グローバル名 'REC' が定義されていませんが、" それはグローバルスコープではなく、ローカルスコープでRECを探していることを意味します。ローカルスコープでrecを定義しているようですが、グローバルで実行しようとしています。実行中の文字列の横にlocals()とglobals()を印刷してみてください。これは、私の作品

More info.

3

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) 
4

これが最初で、あまりにも私を驚かせた、とexecはどちらも非常にトップレベルの定義、または外側の関数内で定義されるような演技奇数コーナーケースのようです。何が起こっているかは関数定義が渡されたlocals()で実行されているように見えますが、定義された関数は実際にはこのlocals命令にアクセスできません。

通常、トップレベルに関数を定義すると、ローカルとグローバルは同じになるので、関数はグローバル内の関数を見ることができるため、関数は内部で可視になります。

関数が別の関数のスコープ内で定義されると、pythonは関数内でアクセスされていることに気づき、 "馬"が外側スコープのバインディングにマップするようにクロージャを作成します。

ここでは奇妙な途中のケースです。execは定義がトップレベルにあるかのように動作しているため、クロージャは作成されません。しかし、地方自治体はグローバルと同じではないため、関数がアクセスできる場所には定義されません。アクセスできない外部のローカルディクトリーでのみ定義されます。

あなたが行うことができます物事のカップルがあります。

  1. は地元の人やグローバルの両方に同じ辞書を使用してください。つまり、 "exec s in locals(),locals()"(またはそれ以上の場合は、自分のdictを使用してください)。 globals()dictだけに同じ効果があります。つまり、 "exec s in mydict" #
  2. funcをクロージャが作成されるように独自の関数内に配置します。例えば

    s=""" 
    def go(): 
        def factorial(x): 
         if x==0: return 1 
         return x*factorial(x-1) 
        print factorial(10) 
    go()""" 
    
  3. グローバルに行くための強制機能()ではなくstephan's answer