Python 스크립트와 동일한 디렉토리에서 파일을 안정적으로 여는 방법


157

나는 현재 실행중인 Python 스크립트와 같은 디렉토리에있는 파일을 단순히 다음과 같은 명령을 사용하여 열었습니다.

open("Some file.txt", "r")

그러나 스크립트를 두 번 클릭하여 Windows에서 스크립트를 실행할 때 잘못된 디렉토리에서 파일을 열려고 시도했습니다.

그 이후로 나는 형태의 명령을 사용했다

open(os.path.join(sys.path[0], "Some file.txt"), "r")

파일을 열 때마다 이것은 내 특정 용도로 작동하지만 sys.path[0]다른 사용 사례에서 실패 할 수 있는지 확실하지 않습니다 .

그래서 내 질문은 : 현재 실행중인 Python 스크립트와 동일한 디렉토리에있는 파일을 여는 가장 신뢰할 수있는 방법은 무엇입니까?

내가 지금까지 알아낼 수 있었던 것은 다음과 같습니다.

  • os.getcwd()그리고 os.path.abspath('')"현재 작업 디렉토리"가 아닌 스크립트 디렉토리를 반환합니다.

  • os.path.dirname(sys.argv[0])그리고 os.path.dirname(__file__)상대 또는 공백 (스크립트가 CWD에있는 경우) 수있는 스크립트를 호출하는 데 사용되는 경로를 반환합니다. 또한 __file__스크립트가 IDLE 또는 PythonWin에서 실행될 때 존재하지 않습니다.

  • sys.path[0]os.path.abspath(os.path.dirname(sys.argv[0]))스크립트 디렉토리를 반환하는 것 같다. 이 둘 사이에 차이점이 있는지 확실하지 않습니다.

편집하다:

방금 내가하고 싶은 것이 "포함 모듈과 같은 디렉토리에 파일을 여는 것"으로 더 잘 설명 될 것이라는 것을 깨달았습니다. 즉, 다른 디렉토리에 작성한 모듈을 가져오고 해당 모듈이 파일을 열면 모듈의 디렉토리에서 파일을 찾고 싶습니다. 내가 찾은 것이 그렇게 할 수 있다고 생각하지 않습니다 ...

답변:


199

나는 항상 사용합니다 :

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__)))

join()호출은 현재 작업 디렉토리를 앞에 추가합니다,하지만 문서는 몇 가지 경로가 절대 인 경우, 왼쪽 다른 모든 경로가 삭제됩니다 말한다. 따라서 절대 경로를 반환하면 getcwd()삭제됩니다 dirname(__file__).

또한이 realpath호출은 발견 된 경우 심볼릭 링크를 확인합니다. Linux 시스템에서 setuptools를 사용하여 배포 할 때 발생하는 문제를 피할 수 있습니다 (스크립트는 /usr/bin/데비안에서 심볼릭 링크되어 있음 ).

다음을 사용하여 동일한 폴더에서 파일을 열 수 있습니다.

f = open(os.path.join(__location__, 'bundled-resource.jpg'));
# ...

이 기능을 사용하여 Windows와 Linux에서 여러 Django 응용 프로그램과 함께 리소스를 번들로 제공하며 매력처럼 작동합니다!


4
사용할 __file__수 없으면 sys.argv[0]대신 을 사용하십시오 dirname(__file__). 나머지는 예상대로 작동합니다. __file__라이브러리 코드에서 sys.argv[0]일부 타사 스크립트를 통해 가져온 경우 코드를 전혀 가리 키지 않을 수 있기 때문에 사용하는 것이 좋습니다.
André Caron

1
이 문제는 실행중인 파일이 직접 인터럽터에서 가져 오거나 가져 오는 경우 달라질 수 있습니다. 파일 과 sys.argv [0] 의 차이점에 대한 내 대답을 참조하십시오 .
Zimm3r

Zimm3r의 답변에 설명 된 변형이 realpath( join( getcwd(), dirname(__file__) ))여기에 설명 된대로 사용하여 해결되었다고 말하는 것이 옳 습니까?
pianoJames

44

파이썬 문서에서 인용하려면 :

프로그램 시작시 초기화 된대로이 목록의 첫 번째 항목 인 path [0]은 Python 인터프리터를 호출하는 데 사용 된 스크립트가 포함 된 디렉토리입니다. 스크립트 디렉토리를 사용할 수없는 경우 (예 : 인터프리터가 대화식으로 호출되거나 표준 입력에서 스크립트를 읽는 경우) path [0]은 빈 문자열로, 현재 디렉토리에서 모듈을 먼저 검색하도록 Python에 지시합니다. 스크립트 디렉토리는 PYTHONPATH의 결과로 삽입 된 항목 앞에 삽입됩니다.

sys.path [0]은 당신이 찾고있는 것입니다.


10
그리고 파일의 전체 경로 : os.path.join(sys.path[0], 'some file.txt'). 모든 시스템에서 공백과 슬래시를 올바르게 처리해야합니다.
Jacktose

이것은 EDIT 이후의 질문이 아니라 첫 번째 질문에 대한 답변입니다.
mcoolive 2016 년

22

여기 내가하는 일이 있습니다

sys.argv는 항상 터미널에 입력하거나 python.exe 또는 pythonw.exe로 파일 경로를 실행할 때 파일 경로로 사용하는 것입니다.

예를 들어 text.py 파일을 여러 가지 방법으로 실행할 수 있습니다. 각각 다른 방법으로 파이썬이 입력 한 경로를 항상 알려줍니다.

    C:\Documents and Settings\Admin>python test.py
    sys.argv[0]: test.py
    C:\Documents and Settings\Admin>python "C:\Documents and Settings\Admin\test.py"
    sys.argv[0]: C:\Documents and Settings\Admin\test.py

이제 파일 이름을 얻을 수 있다는 것을 알고 있습니다. 이제 응용 프로그램 디렉토리를 얻으려면 os.path, 특히 abspath 및 dirname을 사용할 수 있습니다.

    import sys, os
    print os.path.dirname(os.path.abspath(sys.argv[0]))

출력됩니다 :

   C:\Documents and Settings\Admin\

python test.py 또는 python "C : \ Documents and Settings \ Admin \ test.py"를 입력하더라도 항상 출력합니다.

__file__ 사용시 문제 다음 두 파일 test.py를 고려하십시오.

import sys
import os

def paths():
        print "__file__: %s" % __file__
        print "sys.argv: %s" % sys.argv[0]

        a_f = os.path.abspath(__file__)
        a_s = os.path.abspath(sys.argv[0])

        print "abs __file__: %s" % a_f
        print "abs sys.argv: %s" % a_s

if __name__ == "__main__":
    paths()

import_test.py

import test
import sys

test.paths()

print "--------"
print __file__
print sys.argv[0]

"python test.py"의 출력

C:\Documents and Settings\Admin>python test.py
__file__: test.py
sys.argv: test.py
abs __file__: C:\Documents and Settings\Admin\test.py
abs sys.argv: C:\Documents and Settings\Admin\test.py

"python test_import.py"의 출력

C:\Documents and Settings\Admin>python test_import.py
__file__: C:\Documents and Settings\Admin\test.pyc
sys.argv: test_import.py
abs __file__: C:\Documents and Settings\Admin\test.pyc
abs sys.argv: C:\Documents and Settings\Admin\test_import.py
--------
test_import.py
test_import.py

파일에서 볼 수 있듯이 항상 실행중인 파이썬 파일을 제공합니다. 여기서 sys.argv [0]은 항상 인터프리터에서 실행 한 파일을 제공합니다. 필요에 따라 가장 적합한 것을 선택해야합니다.


3
이것은 구현이 문서를 반영한다는 정교한 증거입니다. __file__되는 가정 에 "항상 현재의 파일에 당신에게 경로를 제공"하고 sys.argv[0]있다 생각 "항상 과정을 시작 스크립트의 경로를 제공"에. 어쨌든 __file__호출되는 스크립트에서 사용 하면 항상 정확한 결과를 얻을 수 있습니다.
André Caron

__file__스크립트의 최상위 레벨에 대한 참조가 있으면 예상대로 작동합니다.
Matthew Schinckel

-1

특정 텍스트 파일을 읽는 것과 비슷한 문제가 발생하여 dcolish에서 제공 한 코드를 성공적으로 사용할 수있었습니다. 파일이 Python 파일과 동일한 cwd에 없습니다.


1
답변으로 "감사합니다"를 추가하지 마십시오. 평판 이 충분 하면 도움이되는 질문과 답변투표 할 수 있습니다. - 리뷰에서
Roberto Caboni

-3

나는 이렇게 할 것입니다 :

from os.path import abspath, exists

f_path = abspath("fooabar.txt")

if exists(f_path):
    with open(f_path) as f:
        print f.read()

위의 코드 는 abspath를 사용하여 파일의 절대 경로를 작성하며 normpath(join(os.getcwd(), path))[pydocs에서 온 것] 을 사용하는 것과 같습니다 . 그런 다음 해당 파일이 실제로 존재 하는지 확인한 다음 컨텍스트 관리자를 사용하여 파일 을 열면 파일 핸들에서 close를 호출 할 필요가 없습니다. IMHO,이 방법을 사용하면 장기적으로 많은 고통을 줄일 수 있습니다.


이것은 포스터의 질문에 대답하지 않습니다. dln385 os.path.abspath는 스크립트가 현재 디렉토리에없는 경우 스크립트와 동일한 폴더에있는 파일의 경로를 확인 하지 않는다고 구체적으로 말했습니다 .
André Caron

아! 나는 사용자들이 읽을 원하는 파일과 같은 디렉토리에서이 스크립트를 실행중인 가정 하지 자신의 PYTHONPATH에 뭔가의 모듈 디렉토리에 있습니다. 그건 ... 가정을 가르쳐거야
dcolish

파이썬 런타임이 이와 같은 기능을 사용하여 OS 파일 시스템에서 검색하는 것이 불가능하므로 abspath가 작동하지 않습니다.
akshat thakar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.