8

実行時に入力された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()

NameError:グローバル名'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()

同じエラーが発生します:NameError:グローバル名'rec'が定義されていません

4

4 に答える 4

6

これは私も最初は驚きましたが、 exec がトップレベルの定義のようにも、囲んでいる関数内の定義のようにも振る舞わないという奇妙なケースのようです。関数定義が渡された locals() dict で実行されているように見えますが、定義された関数は実際にはこの locals dict にアクセスできません。

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

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

ここでは、奇妙な中途半端なケースです。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」ディレクティブを配置して、関数を locals ではなく globals() に強制します

于 2009-05-16T09:45:06.793 に答える
5

わたしにはできる:

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()
于 2009-05-16T07:30:48.567 に答える
3

これは私にとってはうまくいきます(追加global rec)。rec(5)localrecを呼び出しますが、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)
于 2009-05-16T08:30:27.423 に答える
0

「NameError: global name 'rec' is not defined」は、ローカル スコープではなく、グローバル スコープで rec を探していることを意味します。ローカルスコープで rec を定義しているように見えますが、グローバルで実行しようとしています。実行している文字列の横に locals() と globals() を出力してみてください。

より詳しい情報。

于 2009-05-16T08:05:53.113 に答える