Python 3のexecfileに代わるものは何ですか?


352

彼らはPython 3で取り消されたようです execfile()

私が見逃している明らかな代替策はありますか?


1
reloadimp.reload3.2以降、として戻ってきました。
Dougal 2013年

18
Pythonをインタラクティブに使用している場合は、IPythonの使用を検討して%run script_nameください。すべてのバージョンのPythonで動作します。
マイケル

1
3.4ためimpであるimportlib (インポートされなければならない):importlib.reload(mod_name)インポートおよび実行しますmod_name
P.ウォーマー2017

3
runfile( "filename.py")の何が問題になっていますか?
マウス

1
ありがとう@mousomer !! runfile()呼び出し側の名前空間で実行するのではなく)独自の名前空間で実行するPythonスクリプトを実行する必要があるため、私はの機能を正確に探していました。私のアプリケーション:属性を使用して、呼び出されたスクリプトのディレクトリをシステムパス(sys.path)に追加します。Python3()で同等の機能__file__を使用している場合、含まれているスクリプトは呼び出し側の名前空間で実行され、呼び出し側のファイル名に解決されます。execfile()exec(open('file.py').read())__file__
mastropi

回答:


389

ドキュメントよると、代わりに

execfile("./filename") 

使用する

exec(open("./filename").read())

見る:


54
なぜ彼らがそのようなことをするのでしょうか?これは以前よりもはるかに冗長です。また、Python3.3では動作しません。exec(open( './ some_file')。read())を実行すると、「そのようなファイルまたはディレクトリはありません」というメッセージが表示されます。'.py'拡張子を含め、 '。/'も除外してみました
JoeyC

25
自明ではありませんが、execfile()のように、例外が発生したときに行番号を提供しません。
KDN、2015

35
closeそのファイルハンドルも必要になります。Python 2からの変更を嫌うもう1つの理由
Rebs

3
その例ではファイルハンドルを閉じる必要のない@Rebs、それは自動的に行われます(少なくとも通常のCPythonでは)
tiho

4
CPythonオブジェクトの@Rebsは、参照カウントが0になるとすぐにガベージコレクションされます。循環参照のみがこれを遅延させる可能性があります(stackoverflow.com/questions/9449489/…)。その場合、read()が戻った直後に発生するはずです。そして、ファイルオブジェクトは削除時に閉じられます(注:このリンクは「常にファイルを閉じる」と明示的に言っています。これは、一般にフォローするのが実際に良い習慣です)
tiho

219

あなたはファイルを読んで自分でコードを実行することになっています。2to3現在の置換

execfile("somefile.py", global_vars, local_vars)

なので

with open("somefile.py") as f:
    code = compile(f.read(), "somefile.py", 'exec')
    exec(code, global_vars, local_vars)

(コンパイル呼び出しは厳密には必要ありませんが、ファイル名をコードオブジェクトに関連付けて、デバッグを少し簡単にします。)

見る:


3
これでうまくいきます。ただし、ローカル引数とグローバル引数を間違った順序で記述していることに気付きました。実際には、exec(object [、globals [、locals]])です。もちろん、もしあなたが元の議論を反転させていたら、2to3はあなたが言ったことを正確に生成します。:)
ネイサンShively-Sanders

3
global_varsとlocal_varsを省略できる場合、ここでのpython3の置き換えはpython2でも機能することを発見して嬉しく思いました。execpython2のステートメントですが、かっこexec(code)が無視されるため機能します。
medmunds 2013年

2
コンパイルを使用するための+1。モジュールがコードがどこから来ているのか判断できなかったため、コンパイルなしで失敗していた私の"somefile.py"封じ込め。inspect.getsourcefile(lambda _: None)inspect
ArtOfWarfare 2014年

16
それは...本当に醜いです。3.xでexecfile()を廃止した理由は何ですか?execfileを使用すると、コマンドライン引数を簡単に渡すこともできます。
aneccodeal 2015年

3
open("somefile.py")とはsomefile.py異なる文字エンコーディングを使用している場合は、正しくない可能性がありますlocale.getpreferredencoding()tokenize.open()代わりに使用できます。
jfs 2016年

73

一方でexec(open("filename").read())、多くの場合の代替として与えられexecfile("filename")、それが重要な詳細ミスexecfileサポートを。

次のPython3.xの関数は、ファイルを直接実行するのと同じ動作をするようにできる限り近いです。それはrunningと一致しますpython /path/to/somefile.py

def execfile(filepath, globals=None, locals=None):
    if globals is None:
        globals = {}
    globals.update({
        "__file__": filepath,
        "__name__": "__main__",
    })
    with open(filepath, 'rb') as file:
        exec(compile(file.read(), filepath, 'exec'), globals, locals)

# execute the file
execfile("/path/to/somefile.py")

ノート:

  • バイナリ読み取りを使用してエンコードの問題を回避
  • ファイルを閉じることが保証されています(Python3.xはこれについて警告します)
  • 定義します__main__。一部のスクリプトは、これがモジュールとしてロードされているかどうかなどを確認するためにこれに依存しています。if __name__ == "__main__"
  • __file__例外メッセージの設定はより適切であり、一部のスクリプトは__file__それらに関連する他のファイルのパスを取得するために使用します。
  • オプションのグローバルおよびローカル引数を取り、それらをその場で変更しexecfileます。実行後に変数を読み戻すことによって定義された変数にアクセスできます。

  • Python2とは異なり、デフォルトでは現在のネームスペース変更されexecfileませ。そのためには、globals()&を明示的に渡す必要がありますlocals()


68

python-devのの上で示唆した最近メーリングリスト、runpyモジュールは、実行可能な代替であるかもしれません。そのメッセージからの引用:

https://docs.python.org/3/library/runpy.html#runpy.run_path

import runpy
file_globals = runpy.run_path("file.py")

には微妙な違いがありますexecfile

  • run_path常に新しい名前空間を作成します。コードをモジュールとして実行するため、グローバルとローカルに違いはありません(そのため、init_globals引数のみがあります)。グローバルが返されます。

    execfile現在のネームスペースまたは指定されたネームスペースで実行されます。localsand のセマンティクスは、globals与えられた場合、クラス定義内のローカルおよびグローバルに似ていました。

  • run_path ファイルを実行できるだけでなく、卵やディレクトリも実行できます(詳細については、ドキュメントを参照してください)。


1
なんらかの理由で、印刷を要求されなかった多くの情報(Anaconda Python 3の「ビルトイン」など)を画面に出力します。これをオフにして、print()で出力した情報のみが視覚化されるようにする方法はありますか?
John Donn 2017年

すべてが格納されている代わりに、現在のワークスペース内のすべての変数を取得することもできますfile_globalsか?これにより、file_globals['...']for every変数を入力する必要がなくなります。
Adriaan 2017

1
「さらに、実行されたコードによって定義された関数とクラスは、runpy関数が返された後に正しく動作することは保証されていません。」ユースケースにもよりますが、注目に値します
nodakai

@Adriaan「globals()。update(file_globals)」を実行します。現在のワークスペースの更新を決定する前にエラーをキャッチできる可能性があるため、個人的にはこの解決策が最も気に入っています。
Ron Kaminsky、

@nodakai情報をありがとう、私はそれを逃した。そのような問題はまだありませんでしたが、何がそれを引き起こすのでしょうか。
Ron Kaminsky、

21

これは、呼び出し元からグローバルとローカルを取得するため、より優れています。

import sys
def execfile(filename, globals=None, locals=None):
    if globals is None:
        globals = sys._getframe(1).f_globals
    if locals is None:
        locals = sys._getframe(1).f_locals
    with open(filename, "r") as fh:
        exec(fh.read()+"\n", globals, locals)

実際、これはpy2に近い方execfileです。上記で投稿された他のソリューションが失敗したpytestsを使用するとき、それは私にとってもうまくいきました。THX!:)
ボリエル

17

あなたはあなた自身の関数を書くことができます:

def xfile(afile, globalz=None, localz=None):
    with open(afile, "r") as fh:
        exec(fh.read(), globalz, localz)

あなたが本当にする必要があるなら...


1
-1:execステートメントはこの方法では機能しません。コードは、Pythonのどのバージョンでも実行できません。
nosklo 2009

6
-1:デフォルトのパラメーター値は関数定義時に評価され、両方globalsを呼び出して、呼び出し元のグローバルおよびローカル名前空間でlocalsexecfile()なく、定義を含むモジュールのグローバル名前空間をポイントします。正しいアプローチはNone、デフォルト値として使用し、inspectモジュールのイントロスペクション機能を介して呼び出し元のグローバルとローカルを決定することです。
Sven Marnach

12

ロードしたいスクリプトが実行したものと同じディレクトリにある場合、おそらく「インポート」が機能しますか?

コードを動的にインポートする必要がある場合は、組み込み関数__ import__とモジュールimpを検討する価値があります。

>>> import sys
>>> sys.path = ['/path/to/script'] + sys.path
>>> __import__('test')
<module 'test' from '/path/to/script/test.pyc'>
>>> __import__('test').run()
'Hello world!'

test.py:

def run():
        return "Hello world!"

Python 3.1以降を使用している場合は、importlibも確認する必要があります。


これが正解でした。このブログは、importlib dev.to / 0xcrypto / dynamic
Nick Brady

9

これが私が持っていたものです(file両方の例でソースコードを含むファイルへのパスにすでに割り当てられています):

execfile(file)

これは私がそれを置き換えたものです:

exec(compile(open(file).read(), file, 'exec'))

私のお気に入りの部分:2番目のバージョンはPython 2と3の両方で問題なく動作します。つまり、バージョンに依存するロジックを追加する必要はありません。


5

ASCIIまたはutf-8以外のPEP-263エンコーディング宣言を使用している場合、上記のパターンは失敗することに注意してください。データのエンコーディングを見つけて、exec()に渡す前に正しくエンコードする必要があります。

class python3Execfile(object):
    def _get_file_encoding(self, filename):
        with open(filename, 'rb') as fp:
            try:
                return tokenize.detect_encoding(fp.readline)[0]
            except SyntaxError:
                return "utf-8"

    def my_execfile(filename):
        globals['__file__'] = filename
        with open(filename, 'r', encoding=self._get_file_encoding(filename)) as fp:
            contents = fp.read()
        if not contents.endswith("\n"):
            # http://bugs.python.org/issue10204
            contents += "\n"
        exec(contents, globals, globals)

3
「上記パターン」とは?StackOverflowの他の投稿を参照するときは、リンクを使用してください。「上記」のような相対的な位置付けの用語は機能しません。回答を(投票、日付、または活動によって)並べ替える方法が3つあり、最も一般的なもの(投票による)は変動しやすいためです。時間の経過とともに、投稿の周りの投稿のスコアは異なります。つまり、それらは再配置され、そのような比較はあまり役に立ちません。
ArtOfWarfare 2014年

非常に良い点です。そして、ほぼ6ヶ月前にこの答え、私が書いたことを考えると、私は意味し、「パターンの上」で想定しstackoverflow.com/a/2849077/165082(残念ながら、あなたが解決するようにクリックする必要があり)、またはより良いまだノームの答え:
エリックを

2
一般に、自分の回答から同じ質問への他の回答を参照したい場合は、たとえば「Noam's Answer」と入力して、参照している回答にテキストをリンクします。 IEの将来のユーザー。これは、ユーザーが自分のアカウント名を変更したり、あまりにも多くの編集が行われたために投稿が共同Wikiになったりするためです。
ArtOfWarfare 2014年

投稿に含まれる特定の「回答」へのURLを、ポスターの回答名を除いてどのように取得しますか?
DevPlayer 2015

ソースを表示してIDを取得します。たとえば、あなたの質問はstackoverflow.com/questions/436198/…になります。私はより良い方法を求めていますが、コメントの近く
Eric

4

また、純粋なPythonソリューションではありませんが、IPythonを使用している場合(おそらくいずれにせよ)、次のことができます。

%run /path/to/filename.py

どちらも簡単です。


1

私はここでは初心者なので、これを見つけたのは幸運かもしれません:

コマンドを使用してインタープリタープロンプト>>>からスクリプトを実行しようとした後

    execfile('filename.py')

「NameError:name 'execfile' is not defined」というメッセージが表示されたため、非常に基本的な

    import filename

それはうまくいきました:-)

これがお役に立てば幸いです。すばらしいヒント、例、そして新規参入者に大きなインスピレーションを与える、見事にコメントされたコードの断片すべてに感謝します。

私はUbuntu 16.014 LTS x64を使用しています。 Python 3.5.2(デフォルト、2016年11月17日、17:05:23)[GCC 5.4.0 20160609] Linux版


0

私にとって最もクリーンなアプローチはimportlib、次のように、パスを使用してファイルをモジュールとしてインポートすることです。

from importlib import util

def load_file(name, path):
    spec = util.spec_from_file_location(name, path)
    module = util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

使用例

ファイルを作ってみましょうfoo.py

print('i got imported')
def hello():
    print('hello from foo')

通常のモジュールのようにインポートして使用します。

>>> foo = load_file('foo', './foo.py')
i got imported
>>> foo.hello()
hello from foo

この手法exec(open(...))は、名前空間が乱雑になったり、不必要にがいじられたりしないため、直接的なアプローチよりも好まれます$PATH

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.