質問

実行時に入力された 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 内でのみ定義されます。

次のようなことができます。

  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. で提案されているように、「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を定義するが、その後世界的に実行しようとするように見えます。地元の人々()と側でグローバル()あなたが実行している文字列を印刷してみます。

詳細情報。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top