2

次のように、値を設定するために exec() ステートメントを使用しています。

foo = 3
def return_4():
    return 4
instruction = 'foo = return_4()'
exec(instruction)                     # <---- WHERE THE MAGIC HAPPENS
print(foo)

予想どおり、これは 4 になります。

私のプログラムには、ルービック キューブを操作する操作があります。この簡素化されたバージョンでは、次の 4 つのことを行います。

  1. 立方体をインスタンス化して、1 つの面を埋めます (「正面左上」と「正面右下」などの略語を使用)。

  2. その正面を回転させる関数を用意します。

  3. キューブと命令のリストを受け取り、それらの命令をキューブに適用して、変更されたキューブを返す「インタープリター」関数を用意します。これが私が「exec」を使用する場所です(そして、破損が発生すると思われる場所です)。

  4. 最後に、面を 1 回回転させる命令を使用して、部分的な立方体でインタープリターを実行します。

+

my_cube = [['FTL', 'FTM', 'FTR',
            'FML', 'FMM', 'FMR',
            'FBL', 'FBM', 'FBR'],
            [],[],[],[],[]] # other faces specified in actual code

def rotate_front(cube):
    front = cube[0]
    new_front = [front[6],front[3],front[0],
                 front[7],front[4],front[1],
                 front[8],front[5],front[2]]
    # ...
    ret_cube = cube
    ret_cube[0] = new_front
    # pdb says we are returning a correctly rotated cube,
    # and calling this directly returns the rotated cube
    return ret_cube

def process_algorithm(cube=default_cube, algorithm=[]):
    return_cube = cube
    for instruction in algorithm:
        exec('return_cube = ' + instruction + '(return_cube)')  # <--- NO MAGIC!
        # ACCORDING TO pdb, return_cube HAS NOT BEEN ROTATED!
    return return_cube

process_algorithm(cube = my_cube, algorithm = ['rotate_front'])

exec(x = y) 形式を x = eval(y) に置き換えると、うまくいくようです。return_cube = eval(命令 + '(return_cube)')

だから多分これは単なる学術的なものです。おもちゃの例は機能するのに、実際のコードは失敗するのはなぜですか? (イコール記号を忘れるなど、明白でばかげたことをしていますか? 私は自分自身を蹴るつもりです、きっと...)

誰でも提供できるヘルプをありがとう。

4

2 に答える 2

5

Python 2.x では、変数ルックアップを関数でアクセスするすべての名前とexecの間で変更するステートメントでした。つまり、最初にローカル スコープを検索して、グローバル スコープをチェックした後に名前が見つかるかどうかを確認します。LOAD_GLOBALLOAD_FASTLOAD_NAME

現在、Python 3.x では、exec関数はこのルックアップを変更できず、結果を評価するスコープを持つ引数を追加しない限り、定義した名前を見つけることはありません。

exec(some_code, globals())

それが機能するには、関数内に追加global my_varして、ルックアップが機能することを確認する必要があります。

これらはモジュールのグローバル名前空間に挿入されることに注意してください...

ところで、なぜ or が必要なのですexecevalalgorithm実際の関数をリストに追加できないのはなぜですか?


補足として、関数の var を変更しないことがわかりますが、変更するalgorithmと、作成したデフォルト値が可変であり、すべての関数呼び出しで使用されるため、望ましくない副作用が発生します。

安全のために、None必要に応じて新しいリストを作成してください。

于 2012-01-02T00:59:18.923 に答える
3

これは質問に答えようとするのではなく、テストケースを拡張して、動作をよりよく確認し、参照用に保存できるようにします。結果は、Windows 上の Python 3.2.2 からのものです。この動作が発生する「理由」については、JBernardo の回答を参照してください。

グローバル スコープから (「おもちゃの例」):

>>> foo = "global-foo"
>>> exec('foo = "global-bar"')
>>> foo
'global-bar'

関数内 (完全なコンテキスト):

>>> def setIt():
        foo = "local-foo"
        exec('foo = "local-bar"')
        return foo

foo = "global-foo"
>>> setIt()
'local-foo'
>>> foo
'global-foo'

指定するとglobals()(まったく機能しませんlocals()):

>>> def setIt():
        foo = "local-foo"
        exec('foo = "local-bar"', globals())
        return foo

>>> foo = "global-foo"
>>> setIt()
'local-foo'
>>> foo
'local-bar'

ハッピーコーディング。

于 2012-01-02T01:09:13.737 に答える