web-dev-qa-db-ja.com

Python 2およびPython 3でのexec関数の動作

次のコードは、_Python2_と_Python3_で異なる出力を提供します。

_from sys import version

print(version)

def execute(a, st):
    b = 42
    exec("b = {}\nprint('b:', b)".format(st))
    print(b)
a = 1.
execute(a, "1.E6*a")
_

_Python2_の出力:

_2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)]
('b:', 1000000.0)
1000000.0
_

_Python3_の出力:

_3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42
_

なぜ_Python2_はb関数内の変数executeexec関数の文字列の値にバインドしますが、_Python3_はバインドしませんこれを行う? _Python2_で_Python3_の動作を実現するにはどうすればよいですか?私はすでに_Python3_のexec関数にグローバルとローカルの辞書を渡そうとしましたが、今のところ何もうまくいきませんでした。

---編集---

Martijnsの回答を読んだ後、_Python3_でこれをさらに分析しました。次の例では、locals()辞書をdとしてexecに指定していますが、_d['b']_はbを印刷する以外の何かを印刷します。

_from sys import version

print(version)

def execute(a, st):
    b = 42
    d = locals()
    exec("b = {}\nprint('b:', b)".format(st), globals(), d)
    print(b)                     # This prints 42
    print(d['b'])                # This prints 1000000.0
    print(id(d) == id(locals())) # This prints True
a = 1.
execute(a, "1.E6*a")

3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42
1000000.0
True
_

dlocals()のIDの比較は、それらが同じオブジェクトであることを示しています。ただし、これらの条件下では、bは_d['b']_と同じである必要があります。私の例では何が間違っていますか?

36
Holger

exec in Python 2とexec() in Python 3)には大きな違いがあります。exec関数としてですが、実際にはPython 2.のstatement)です.

この違いのため、Python 2.で可能であったとしても、execを使用してPython 3で関数スコープのローカル変数を変更することはできません。以前に宣言された変数でさえありません。

locals()は、一方向のローカル変数のみを反映します。以下は2でも3でも機能しませんでした。

_def foo():
    a = 'spam'
    locals()['a'] = 'ham'
    print(a)              # prints 'spam'
_

Python 2、execステートメントを使用すると、コンパイラはローカルスコープの最適化をオフにすることを知っていました(たとえば、_LOAD_FAST_から_LOAD_NAME_への切り替え)ローカルスコープとグローバルスコープの両方で変数を検索します)exec()が関数である場合、そのオプションは使用できなくなり、関数スコープは現在always最適化されています。

さらに、Python 2、execステートメントは、locals()で見つかったすべての変数を_PyFrame_LocalsToFast_を使用して関数localsに明示的にコピーします。ただし、 globalsおよびlocalsパラメーターは指定されていません。

適切な回避策は、exec()呼び出しに新しい名前空間(辞書)を使用することです。

_def execute(a, st):
    namespace = {}
    exec("b = {}\nprint('b:', b)".format(st), namespace)
    print(namespace['b'])
_

exec() documentation は、この制限について非常に明示的です:

注:デフォルトのlocalsは、以下の関数locals()の説明に従って動作します。デフォルトlocalsディクショナリにしようとしないでください。関数exec()が戻った後にローカルのコードの効果を確認する必要がある場合は、明示的なlocals辞書を渡します。

41
Martijn Pieters

Python3のバグだと思います。

_def u():
    exec("a=2")
    print(locals()['a'])
u()
_

「2」を出力します。

_def u():
    exec("a=2")
    a=2
    print(a)
u()
_

「2」を出力します。

だが

_def u():
    exec("a=2")
    print(locals()['a'])
    a=2
u()
_

失敗する

_Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in u
KeyError: 'a'
_

---編集---もう一つの興味深い振る舞い:

_def u():
    a=1
    l=locals()
    exec("a=2")
    print(l)
u()
def u():
    a=1
    l=locals()
    exec("a=2")
    locals()
    print(l)
u()
_

出力

_{'l': {...}, 'a': 2}
{'l': {...}, 'a': 1}
_

そしてまた

_def u():
    l=locals()
    exec("a=2")
    print(l)
    print(locals())
u()
def u():
    l=locals()
    exec("a=2")
    print(l)
    print(locals())
    a=1
u()
_

出力

_{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}}
_

どうやら、ローカルでのexecのアクションは次のとおりです。

  • 変数がexec内で設定され、この変数がローカル変数であった場合、execは内部辞書(locals()によって返されるもの)を変更し、それを返しません。元の状態。 locals()を呼び出すと、辞書が更新され(python documentation)のセクション2で説明されているように)、exec内に設定された値が忘れられます。 locals()を呼び出して辞書を更新することは、ドキュメント化されているためpython3のバグではありませんが、直観的ではありません。また、exec内のローカルの変更は関数のローカルはpython2との文書化された違いです(ドキュメントでは「関数exec()が戻った後にローカルのコードの効果を確認する必要がある場合は明示的なローカル辞書を渡す」と書かれています)。
  • 変数がexec内に設定され、この変数が以前に存在しなかった場合、execは、後で変数が設定されない限り、内部辞書を変更します。 locals()が辞書を更新する方法にバグがあるようです。このバグは、execの後にlocals()を呼び出すことにより、exec内で設定された値にアクセスできます。
5
LRGH

まとめると:

  • Python 2にも、Python 3にもバグはありません。
  • execの異なる動作は、Python 2のステートメントであるexecに由来しますが、Python 3。

ご注意ください:

ここで新しいことは何も伝えません。これは、他のすべての回答とコメントにある真実の集合体です。私がここで試みるのは、より曖昧な詳細のいくつかに光を当てることです。

Python 2とPython 3の唯一の違いは、実際にexecは囲んでいる関数のローカルスコープを変更できることです。 in Python 2(ステートメントであり、現在のローカルスコープにアクセスできるため)およびin Python 3(現在は関数であるため) 、したがって、独自のローカルスコープで実行されます)。

ただし、刺激はexecステートメントとは関係なく、1つの特別な動作の詳細にのみ起因します。

locals()は何かを返します。これを「locals()の呼び出し後、常にローカルスコープ内のすべての変数のみを参照するスコープごとに変更可能なシングルトン」と呼びます。

locals()の動作は、Python 2と3の間で変化しなかったことに注意してください。したがって、この動作はexecの動作方法の変更とともに不安定ですが、常にそこにあった詳細を公開するだけではありません。

「ローカルスコープ内の変数を参照するスコープごとの可変シングルトン」とはどういう意味ですか?

  • これは_scope-wise singleton_です。同じスコープ内でlocals()を呼び出す頻度に関係なく、返されるオブジェクトは常に同じです。
    • したがって、id(d) == id(locals())という観察は、dlocals()が同じオブジェクト、同じシングルトンを参照しているためです。別のオブジェクトを取得しますが、同じスコープではこの単一のオブジェクトのみが表示されます)。
  • 通常のオブジェクトであるため、mutableであるため、変更できます。
    • locals()は、オブジェクト内のすべてのエントリがローカルスコープ内の変数を再度参照するように強制します。
    • オブジェクト内の何かを(dを介して)変更すると、通常の変更可能なオブジェクトであるため、これによりオブジェクトが変更されます。
  • オブジェクトのすべてのエントリは_references to the variables in the local scope_であるため、シングルトンのこれらの変更はローカルスコープに反映されません。したがって、エントリを変更すると、これらはシングルトンオブジェクトを変更し、「参照を変更する前に参照が指していた場所」の内容は変更しません(したがって、ローカル変数は変更しません)。

    • Pythonでは、文字列と数値は変更できません。つまり、エントリに何かを割り当てた場合、エントリが指すオブジェクトを変更せずに、新しいオブジェクトを導入し、エントリへの参照を割り当てます。例:

      _a = 1
      d = locals()
      d['a'] = 300
      # d['a']==300
      locals()
      # d['a']==1
      _

    最適化に加えて、これは次のことを行います。

    • 新しいオブジェクトNumber(1)を作成します-これは他のシングルトンであるBTWです。
    • このNumber(1)へのポインタを_LOCALS['a']_に保存します
      (ここで、LOCALSは内部ローカルスコープでなければなりません)
    • まだ存在しない場合は、SINGLETONオブジェクトを作成します
    • SINGLETONを更新して、LOCALSのすべてのエントリを参照するようにします
    • SINGLETONのポインターを_LOCALS['d']_に格納します
    • 数値(300)を作成します。これはではなくシングルトン、BTWです。
    • これらのNumber(300)へのポインターを_d['a']_に格納します
    • したがって、SINGLETONも更新されます。
    • ただし、LOCALSnot更新されるため、ローカル変数aまたは_LOCALS['a']_は引き続きNumber(1 )
    • これで、locals()が再度呼び出され、SINGLETONが更新されます。
    • dSINGLETONではなくLOCALSを参照しているため、dも変更されます!

この驚くべき詳細の詳細、なぜ_1_がシングルトンであるのに_300_はそうでないのか、 https://stackoverflow.com/a/30635 を参照してください

ただし、忘れないでください。数字は不変なので、数字を別の値に変更しようとすると、別のオブジェクトを効率的に作成できます。

結論:

Python 2をPython 3(コードを変更する場合を除く)の方法はありません)のexec動作に戻すことはできません。プログラムフロー外のローカル変数を変更します。

ただし、Python 3の動作をPython 2にすることができます。これにより、今日、あなたは、 Python 3またはPython 2.これは、(新しい)Python 2でexec関数のような引数も(実際、これらは2または3タプルです)、Python 3から知られる同じセマンティクスで同じ構文を使用できます。

_exec "code"
_

(Python 2)でのみ動作します)は(Python 2および3で動作します):

_exec("code", globals(), locals())
_

ただし、_"code"_はこの方法でローカルの囲みスコープを変更できないことに注意してください。 https://docs.python.org/2/reference/simple_stmts.html#exec も参照してください

最後の言葉:

Python 3でのexecの変更は適切です。最適化のため。

Python 2では、不変のコンテンツを含むすべてのローカル変数の状態が予期せず変更される可能性があるため、exec全体で最適化できませんでした。関数呼び出しの_は、他のすべての関数と同様にexec()にも適用されます。

3
Tino

正確に説明できないのではないかと思いますが、基本的には関数内のbがローカルであり、exec()がグローバルbに割り当てられているように見えるという事実から来ています。関数内でグローバルであるようにbを宣言する必要がありますand execステートメント内で。

これを試して:

_from sys import version

print(version)

def execute1(a, st):
    b = 42
    exec("b = {}\nprint('b:', b)".format(st))
    print(b)

def execute2(a, st):
    global b
    b = 42
    exec("global b; b = {}\nprint('b:', b)".format(st))
    print(b)

a = 1.
execute1(a, "1.E6*a")
print()
execute2(a, "1.E6*a")
print()
b = 42
exec("b = {}\nprint('b:', b)".format('1.E6*a'))
print(b)
_

それは私に与えます

_3.3.0 (default, Oct  5 2012, 11:34:49) 
[GCC 4.4.5]
b: 1000000.0
42

b: 1000000.0
1000000.0

b: 1000000.0
1000000.0
_

関数の外側で、グローバルbが自動的に選択されることがわかります。関数内では、ローカルbを印刷しています。

exec()は常にグローバルbを最初に使用するので、execute2()ではexec()関数内で宣言する必要がないと思っていたことに注意してください。 。しかし、私はそれがうまくいかないことがわかります(これは私が正確に説明できない部分です)。

1
user707650