Python 3에서 execfile의 대안은 무엇입니까?


352

파이썬 3에서는 스크립트를 제거하여 스크립트를 빠르게로드하는 쉬운 방법을 모두 취소 한 것으로 보입니다. execfile()

내가 놓친 명백한 대안이 있습니까?


1
reload로 돌아 imp.reload3.2 이후.
— Dougal

18
대화식으로 Python을 사용하는 경우 IPython 사용을 고려하십시오 %run script_name. 모든 버전의 Python에서 작동합니다.
— Michael

1
3.4 imp는 importlib (반드시 가져와야 함) importlib.reload(mod_name)가져 오기 및 실행 mod_name합니다.
— P. Wormer

3
runfile ( "filename.py")의 문제점은 무엇입니까?
— mousomer

1
감사합니다 @ mousomer !! 호출 네임 스페이스 runfile()에서 실행하는 대신 자체 네임 스페이스에서 실행되는 Python 스크립트를 실행해야했기 때문에 기능을 정확하게 찾고있었습니다 . 내 응용 프로그램 : 속성을 사용하여 호출 된 스크립트의 디렉토리를 시스템 경로 ( )에 추가하십시오 : Python 3 ( ) 에서 사용 하거나 이에 상응하는 경우 포함 된 스크립트가 호출 네임 스페이스에서 실행되므로 호출 파일 이름으로 해석됩니다 . sys.path__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

35
close그 파일 핸들도 필요합니다 . 파이썬 2의 변화를 싫어하는 또 다른 이유
— Rebs

3
@Rebs이 예제에서 파일 핸들을 닫을 필요는 없습니다. 자동으로 (적어도 정규 CPython에서)
— tiho

4
CPython 객체의 @Rebs는 참조 횟수가 0이 되 자마자 가비지 수집됩니다. 순환 참조 만이 지연 될 수 있습니다 ( stackoverflow.com/questions/9449489/… ). 이 경우 read ()가 반환 된 직후에 발생해야합니다. 그리고 파일 객체는 삭제 될 때 닫힙니다 (NB :이 링크는 명시 적으로 "항상 파일을 닫습니다"라고 명시되어 있습니다. 일반적으로 따르는 것이 좋습니다)
— 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는 당신이 말한 것을 정확하게 만들 것입니다. :)
— Nathan Shively-Sanders

3
global_vars 및 local_vars를 생략 할 수있는 경우 여기서 python3 대체는 python2에서도 작동합니다. execpython2의 문장 이지만 파렌 exec(code)이 무시되기 때문에 작동합니다.
— medmunds

2
컴파일 사용시 +1 내가 "somefile.py"포함 inspect.getsourcefile(lambda _: None)때문에 컴파일하지 않고 실패 된 inspect코드에서오고 어디 모듈은 확인할 수 없습니다.
— ArtOfWarfare

16
그건 .. 정말 못 생겼어 왜 3.x에서 execfile ()을 제거했는지 알고 있습니까? execfile을 사용하면 명령 줄 인수를 쉽게 전달할 수 있습니다.
— 초에 일화

3
open("somefile.py")somefile.py와 다른 문자 인코딩을 사용하는 경우 올바르지 않을 수 있습니다 locale.getpreferredencoding(). tokenize.open()대신 사용할 수 있습니다.
— jfs

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현재 네임 스페이스 또는 지정된 네임 스페이스에서 실행됩니다. 주어진 경우 locals와 의 의미 globals는 클래스 정의 내부의 지역 및 전역과 유사합니다.

  • run_path 파일뿐만 아니라 계란과 디렉토리도 실행할 수 있습니다 (자세한 내용은 설명서를 참조하십시오).


1
어떤 이유로, 화면에 인쇄하도록 요청되지 않은 많은 정보를 출력합니다 ( Anaconda Python 3의 ' builtins '등). print ()로 출력 한 정보 만 시각화되도록 이것을 끄는 방법이 있습니까?
— John Donn

현재 작업 공간에서 모든 변수를 저장하는 대신 모든 변수를 가져올 수 file_globals있습니까? 이렇게하면 file_globals['...']모든 변수에 대해 입력해야 합니다.
— Adriaan

1
또한, 실행 된 코드로 정의 된 함수 및 클래스는 런피 함수가 반환 된 후에 올바르게 작동하지 않을 수 있습니다. 유스 케이스에 따라 주목할만한 가치
— 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. 위에 게시 된 다른 솔루션이 실패한 pytest를 사용할 때도 효과가있었습니다. 고마워! :)
— Boriel

17

당신은 당신의 자신의 함수를 작성할 수 있습니다 :

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

정말로 필요하다면 ...


1
-1 : exec 명령이이 방식으로 작동하지 않습니다. 코드는 어떤 버전의 파이썬에서도 실행되지 않습니다.
— nosklo

6
-1 : 기본 파라미터 값은 모두 만드는 함수 정의시 평가 globals와 locals의 정의에 포함 된 모듈 FO 글로벌 네임 스페이스 포인트 execfile()호출자의 글로벌 및 로컬 공간에 대신한다. 올바른 접근 방식은 None기본값 으로 사용 하고 inspect모듈 의 내부 검사 기능을 통해 발신자의 전역 및 지역을 결정하는 것 입니다.
— Sven Marnach

12

로드하려는 스크립트가 실행하는 스크립트와 동일한 디렉토리에 있으면 "import"가 작업을 수행합니까?

코드를 동적으로 가져와야하는 경우 내장 함수 __ 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-importing-stuff-in-python--1805
— Nick Brady

9

여기 내가 가진 것이 있습니다 ( file두 예제 모두에서 소스 코드로 파일 경로에 이미 할당되어 있습니다).

execfile(file)

여기 내가 대체 한 것이 있습니다.

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

내가 가장 좋아하는 부분 : 두 번째 버전은 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

아주 좋은 지적입니다. 그리고 거의 6 개월 전이 대답 내가 쓴 것을 주어, 나는 의미 "패턴 위의"에 의해 가정 stackoverflow.com/a/2849077/165082 (불행하게도 당신이 결의에 클릭해야), 또는 더 나은 아직 노암의 대답 :
— 에릭

2
일반적으로 답변에서 동일한 질문에 대한 다른 답변을 참조하려면 "Noam 's Answer"(예 :)를 입력하고 텍스트가 내가 언급 한 답변과 연결되지 않은 경우를 대비하여 텍스트를 연결합니다. 사용자는 자신의 계정 이름을 변경하거나 게시물을 너무 많이 편집하여 공동 위키가되므로 향후 사용자는 IE입니다.
— ArtOfWarfare

포스터의 답변 이름을 제외하고 게시물에 특정 "응답"에 대한 URL을 어떻게 얻습니까?
— DevPlayer

소스를보고 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

그것은 잘 작동했습니다 :-)

나는 이것이 도움이되기를 바랍니다. 훌륭한 힌트, 예제 및 새로 등장한 사람들에게 큰 영감을주는 모든 코드 주석에 대해 감사합니다!

우분투 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.