8

一部のPython2コードでステートメントを使用しておりexec、そのコードをPython2とPython3の両方と互換性を持たせようとしていますが、Python3ではexecステートメントから関数に変更されています。Python 2と3の両方と互換性のあるコードを書くことは可能ですか?Python2とPython3のデュアル開発について読んだことがありますが、execステートメント/関数の変更に対する特定のソリューションに興味があります。

私はそれexecが一般的に推奨されていないことを理解していますが、私はPyDevの上にライブコーディングを実装するEclipseプラグインを構築しています。詳細については、プロジェクトページを参照してください。

4

3 に答える 3

13

一部のPython移植ガイドはexec 間違っています:

グローバルディクショナリまたはローカルディクショナリを渡す必要がある場合は、Python2用とPython3用の2つの異なる実装でカスタム関数を定義する必要があります。通常どおりsix、これには。と呼ばれる優れた実装が含まれていexec_()ます。

Python2コードをPython3(*)に移植するために、このようなカスタム関数は必要ありません。あなたは、Python 2で行うことができexec(code)、それは機能しますexec(code, globs)exec(code, globs, locs)

Pythonは、存在する限り、Python3互換の「構文」を常に受け​​入れてきました。この理由は、Python2とPython1(?!)には、関数であるPython0.9.8との下位互換性を維持するためのハックがあるためです。ここで、渡された場合は2タプルとして解釈され、3タプルの場合はとして解釈されます。はい、インは不必要に複雑です。execexecexecexec(code, globals)(code, globals, locals)exec_six

したがって、

exec(source, global_vars, local_vars)

CPython 0.9.9、1.x、2.x、3.xでも同じように機能することが保証されています。また、Jython 2.5.2、PyPy 2.3.1(Python 2.7.6)、IronPython2.6.1で動作することも確認しました。

Jython 2.5.2 (Release_2_5_2:7206, Mar 2 2011, 23:12:06) 
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_25
Type "help", "copyright", "credits" or "license" for more information.
>>> exec('print a', globals(), {'a':42})
42

*)微妙な違いがあるため、すべてのPython3コードがPython2で機能するわけではありません。

繰り返しになりますが、エッジケースの解決策は、使用をやめて代わりに使用することです(execモードコンパイルされたバイトコードを実行するために使用できます)。evalevalcompileexec

def print_arg(arg):
    def do_print():
        print(arg)

    eval(compile('do_print(); print("it really works")', '<string>', 'exec'))

execの内部、evalおよびPythoncompileのeval、exec、およびコンパイルの違いについて、より詳細な回答を書きました。

于 2015-04-26T10:34:24.707 に答える
6

AnttiがPython2がPython3exec関数構文をサポートしているという回答を投稿する前に、これを行うためのいくつかのオプションを見つけました。

最初の式は、長さが2または3のタプルの場合もあります。この場合、オプションの部分は省略できます。フォームexec(expr, globals)はと同等ですがexec expr in globals、フォームexec(expr, globals, locals)はと同等exec expr in globals, localsです。タプル形式のexecは、Python 3との互換性を提供します。ここで、execはステートメントではなく関数です。

何らかの理由でそれを使用したくない場合は、ここに私が見つけた他のすべてのオプションがあります。

スタブのインポート

2つの異なるインポートスタブを宣言し、現在のインタープリターで機能する方をインポートできます。これは、PyDevソースコードで見たものに基づいています。

メインモジュールに入れるものは次のとおりです。

try:
    from exec_python2 import exec_code #@UnusedImport
except:
    from exec_python3 import exec_code #@Reimport

これがあなたが入れたものですexec_python2.py

def exec_code(source, global_vars, local_vars):
    exec source in global_vars, local_vars

これがあなたが入れたものですexec_python3.py

def exec_code(source, global_vars, local_vars):
    exec(source, global_vars, local_vars)

EvalのExec

Ned Batchelderexecは、Python 3で構文エラーが発生しないように、ステートメントを呼び出しでラップする手法を投稿しましevalた。これは賢いですが、明確ではありません。

# Exec is a statement in Py2, a function in Py3

if sys.hexversion > 0x03000000:
    def exec_function(source, filename, global_map):
        """A wrapper around exec()."""
        exec(compile(source, filename, "exec"), global_map)
else:
    # OK, this is pretty gross.  In Py2, exec was a statement, but that will
    # be a syntax error if we try to put it in a Py3 file, even if it isn't
    # executed.  So hide it inside an evaluated string literal instead.
    eval(compile("""\
def exec_function(source, filename, global_map):
    exec compile(source, filename, "exec") in global_map
""",
    "<exec_function>", "exec"
    ))

6つのパッケージ

6つのパッケージは、Python2とPython3の両方で実行されるコードを記述するための互換性ライブラリです。両方のバージョンに変換するexec_()関数があります。私はそれを試していません。

于 2012-10-09T22:17:56.623 に答える
1

これを行う必要があり、6つを使用できませんでした。また、私のバージョンのPythonは、自由変数を使用したネストされた関数で使用したため、@Anttiのメソッドをサポートしていません。不要なインポートもしたくありませんでした。これが私が思いついたものです。これはおそらく、メソッドではなくモジュールにある必要があります。

try:
  # Try Python2.
  _exec_impls = {
    0: compile('exec code', '<python2>', 'exec'),
    1: compile('exec code in _vars[0]', '<python2>', 'exec'),
    2: compile('exec code in _vars[0], _vars[1]', '<python2>', 'exec'),
  }

  def _exec(code, *vars):
    impl = _exec_impls.get(len(vars))
    if not impl:
      raise TypeError('_exec expected at most 3 arguments, got %s' % (len(vars) + 1))
    return eval(impl, { 'code': code, '_vars': vars })

except Exception as e:
  # Wrap Python 3.
  _exec = eval('exec')

その後、_execPython3バージョンのように動作します。文字列を渡すか、を実行することができますcompile()。おそらく必要なグローバルまたはローカルを取得できないため、次のように渡します。

def print_arg(arg):
  def do_print():
    print(arg)
  _exec('do_print(); do_print(); do_print()', globals(), locals())

print_arg(7)  # Prints '7'

か否か。私はStackOverflowの投稿であり、警官ではありません。

更新:

使ってみませんeval()か? eval()期待しますが、ステートメントを期待します。式を取得したばかりの場合、有効な式はすべて有効なステートメントであるため、何を使用してもかまいませんが、その逆は当てはまりません。メソッドを実行するだけで、何も返されない場合でも式になります。暗黙の返品があります。exec()None

passこれは、次のステートメントであるevalを試行することによって示されます。

>>> exec('pass')
>>> eval('pass')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    pass
       ^
SyntaxError: unexpected EOF while parsing
于 2016-12-28T20:16:42.840 に答える