현재 스크립트 디렉토리를 올바르게 결정하는 방법은 무엇입니까?


260

파이썬에서 현재 스크립트 디렉토리를 결정하는 가장 좋은 방법은 무엇입니까?

파이썬 코드를 호출하는 많은 방법으로 인해 좋은 해결책을 찾기가 어렵다는 것을 알았습니다.

몇 가지 문제가 있습니다 :

  • __file__로 스크립트를 실행하면 정의되지 않습니다 exec.execfile
  • __module__ 모듈에서만 정의

사용 사례:

  • ./myfile.py
  • python myfile.py
  • ./somedir/myfile.py
  • python somedir/myfile.py
  • execfile('myfile.py') (다른 스크립트에서 다른 디렉토리에 있으며 다른 현재 디렉토리를 가질 수 있습니다.

완벽한 솔루션이 없다는 것을 알고 있지만 대부분의 경우를 해결하는 최선의 방법을 찾고 있습니다.

가장 많이 사용되는 방법 os.path.dirname(os.path.abspath(__file__))이지만 다른 스크립트를 사용하여 스크립트를 실행하면 실제로 작동하지 않습니다 exec().

경고

현재 디렉토리를 사용하는 모든 솔루션이 실패합니다. 이는 스크립트가 호출되는 방식에 따라 다를 수 있거나 실행중인 스크립트 내에서 변경 될 수 있습니다.


1
파일의 출처를 알아야 할 위치를 더 구체적으로 지정할 수 있습니까? -파일 (include-aware host)을 가져 오는 코드 또는 가져온 파일에서? (자체 인식 노예)
신디사이저

3
론 Kalian의 참조 pathlib: 당신은 파이썬 3.4 이상 사용하는 경우 솔루션을 stackoverflow.com/a/48931294/1011724

솔루션은 코드에서 현재 디렉토리를 사용하지 않고 구성 파일을 사용하는 것입니까?
ZhaoGang

일시 : 재미있는 발견은, 내가 방금 만든 python myfile.py쉘에서 작동하지만, 모두 :!python %:!python myfile.py내에서 정력 실패 지정된 경로를 찾을 수 없습니다. 이것은 꽤 성가신 일입니다. 누구 든지이 이유와 잠재적 해결 방법에 대해 의견을 말할 수 있습니까?
inVader

답변:


231
os.path.dirname(os.path.abspath(__file__))

실제로 당신이 얻을 최고입니다.

exec/ execfile; 로 스크립트를 실행하는 것은 일반적이지 않습니다 . 일반적으로 모듈 인프라를 사용하여 스크립트를로드해야합니다. 이 방법을 사용해야하는 경우 스크립트에서 파일 이름을 읽을 수 있도록 설정 __file__하는 것이 좋습니다 globals.

실행 코드에서 파일 이름을 얻는 다른 방법은 없습니다. CWD가 완전히 다른 위치에있을 수 있습니다.


2
절대 말하지 않습니까? 이것에 따르면 : stackoverflow.com/a/18489147 응답 크로스 플랫폼 솔루션은 abspath (getsourcefile (lambda : 0))입니까? 아니면 내가 놓친 다른 것이 있습니까?
Jeff Ellen

131

를 통해 스크립트가 호출되는 경우를 실제로 다루려면 모듈을 execfile(...)사용 inspect하여 파일 이름 (경로 포함)을 추론 할 수 있습니다 . 내가 아는 한, 이것은 귀하가 나열된 모든 경우에 적용됩니다.

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

4
이것이 실제로 가장 강력한 방법이라고 생각하지만 OP의 명시 적 요구에 의문을 제기합니다. 개발자가 실행 모듈과 관련된 위치에서 데이터 파일을 사용하는 경우 종종이 작업을 수행하지만 IMO 데이터 파일은 알려진 위치에 배치해야합니다.
Ryan Ginstrom 2016 년

14
@Ryan LOL, 다중 플랫폼이며 모듈과 함께 제공되는 "알려진 위치"를 정의 할 수 있다면 좋을 것입니다. 유일한 안전한 위치는 스크립트 위치라는 것입니다. 이것은 스크립트가이 위치에 써야한다는 것을 의미하지는 않지만 데이터를 읽으려면 안전합니다.
소린

1
여전히 해결책은 좋지 않으며 chdir()함수 전에 호출하려고 하면 결과가 변경됩니다. 또한 다른 디렉토리에서 파이썬 스크립트를 호출하면 결과가 변경되므로 좋은 해결책이 아닙니다.
소린

2
os.path.expanduser("~")사용자의 디렉토리를 얻는 플랫폼 간 방법입니다. 불행히도, 이것은 응용 프로그램 데이터를 어디에 저장할지에 대한 Windows 모범 사례가 아닙니다.
Ryan Ginstrom

6
@sorin : chdir()스크립트를 실행하기 전에 시도했습니다 . 올바른 결과를 생성합니다. 다른 디렉토리에서 스크립트를 호출하려고 시도했지만 작동합니다. 결과는 inspect.getabsfile()기반 솔루션 과 동일 합니다 .
jfs

43
#!/usr/bin/env python
import inspect
import os
import sys

def get_script_dir(follow_symlinks=True):
    if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze
        path = os.path.abspath(sys.executable)
    else:
        path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        path = os.path.realpath(path)
    return os.path.dirname(path)

print(get_script_dir())

CPython, Jython, Pypy에서 작동합니다. 스크립트를 사용하여 스크립트를 실행하면 작동합니다 execfile()( sys.argv[0]그리고 __file__기반 솔루션은 여기서 실패합니다). 스크립트가 실행 가능한 zip 파일 (/ eg) 안에 있으면 작동합니다 . 스크립트가 PYTHONPATH=/path/to/library.zip python -mscript_to_runzip 파일에서 "가져온"( ) 경우 작동 합니다. 이 경우 아카이브 경로를 반환합니다. 스크립트가 독립형 실행 파일 ( sys.frozen) 로 컴파일 된 경우 작동합니다 . 심볼릭 링크에서 작동합니다 ( realpath심볼릭 링크 제거). 대화식 인터프리터에서 작동합니다. 이 경우 현재 작업 디렉토리를 반환합니다.


PyInstaller와 완벽하게 작동합니다.
gaborous

1
getabsfile(..)대한 문서에inspect 언급되지 않은 이유 가 있습니까? 해당 페이지와 연결된 소스에 나타납니다.
Evgeni Sergeev 12

@EvgeniSergeev 버그 일 수 있습니다. 그것은 주위에 간단한 래퍼 getsourcefile(), getfile()설명되어 있습니다.
jfs

24

Python 3.4 이상에서는 더 간단한 pathlib모듈을 사용할 수 있습니다 .

from inspect import currentframe, getframeinfo
from pathlib import Path

filename = getframeinfo(currentframe()).filename
parent = Path(filename).resolve().parent

2
뛰어난 단순성!
Cometsong

3
아마도 모듈 Path(__file__)을 사용할 필요가 없습니다 inspect.
Peque

@Peque는 부모 디렉토리가 아닌 현재 파일의 이름을 포함한 경로를 생성합니다. 동일한 디렉토리에있는 파일을 가리 키기 위해 현재 스크립트 디렉토리를 가져 오려고 시도하는 경우 (예 : 스크립트와 동일한 디렉토리에 구성 파일을로드 할 것으로 예상하는 경우) OP가 원할 때 Path(__file__)제공/path/to/script/currentscript.py/path/to/script/
Davos

8
오, 나는 당신이 inspect 모듈을 피하고 parent = Path(__file__).resolve().parent 훨씬 더 좋은 것을 사용한다는 것을 오해했다 .
Davos

3
@Dut A.이 경우에는 .joinpath()(또는 /연산자)를 사용해야합니다 +.
유진 야마 쉬

13

그만큼 os.path...방법은 파이썬 2의 '할 일'입니다.

Python 3에서는 다음과 같이 스크립트 디렉토리를 찾을 수 있습니다.

from pathlib import Path
cwd = Path(__file__).parents[0]

11
아니면 그냥 Path(__file__).parent. 그러나 현재 작업 디렉토리 가 아니라 파일의 디렉토리 인cwd 잘못된 이름 입니다. 그것들은 같을 수 있지만, 보통은 그렇지 않습니다.
Nuno André

5

사용 os.path.dirname(os.path.abspath(__file__))되는 케이스가 실제로 필요한지 여부를 신중하게 사용 하고 조사하십시오 exec. 스크립트를 모듈로 사용할 수없는 경우 문제가 발생할 수 있습니다.

Zen of Python # 8 을 명심하십시오 . 유용 사례에 대한 좋은 주장이 있다고 생각 exec되면 문제의 배경에 대해 더 자세히 알려주십시오.


2
exec ()로 실행하지 않으면 디버거 컨텍스트가 느슨해집니다. 또한 exec ()는 새로운 프로세스를 시작하는 것보다 훨씬 빠릅니다.
sorin

@sorin exec와 새로운 프로세스의 시작에 관한 문제는 아니므로 이것은 짚맨 논쟁입니다. 가져 오기 또는 함수 호출을 사용하는 대 exec의 문제입니다.
wim

4

할 것이다

import os
cwd = os.getcwd()

당신이 원하는 것을합니까? "현재 스크립트 디렉토리"가 정확히 무엇을 의미하는지 잘 모르겠습니다. 제공 한 사용 사례에 대해 예상되는 결과는 무엇입니까?


3
도움이되지 않습니다. @bogdan이 호출 스택 맨 위에있는 스크립트의 디렉토리를 찾고 있다고 생각합니다. 즉, 모든 경우에 'myfile.py'가있는 디렉토리를 인쇄해야합니다. 아직 방법은 해당 전화 파일의 디렉토리를 인쇄하는 것 exec('myfile.py'), 같은 __file__sys.argv[0].
Zhang18

그래, 그 말이 맞아 나는 @bogdan이 간단한 것을 간과하지 않도록하고 싶었고 정확히 그들이 원하는 것을 말할 수 없었습니다.
Will McCutchen

3

먼저 익명의 코드를 삽입하는 방법에 대해 이야기하고 있다면 유스 케이스가 누락 된 것입니다.

code.compile_command()
code.interact()
imp.load_compiled()
imp.load_dynamic()
imp.load_module()
__builtin__.compile()
loading C compiled shared objects? example: _socket?)

그러나 진짜 질문은, 당신의 목표는 무엇입니까-당신은 일종의 보안을 시행하려고합니까? 또는 당신은 무엇을로드하는 것에 관심이 있습니까?

보안에 관심이있는 경우 exec / execfile을 통해 가져 오는 파일 이름은 중요하지 않습니다. rexec 를 사용해야 합니다. 다음을 제공합니다.

이 모듈에는 r_eval (), r_execfile (), r_exec () 및 r_import () 메소드를 지원하는 RExec 클래스가 포함되어 있습니다.이 메소드는 표준 Python 함수 eval (), execfile () 및 exec 및 import 문의 제한된 버전입니다. 이 제한된 환경에서 실행되는 코드는 안전하다고 간주되는 모듈 및 기능에만 액세스 할 수 있습니다. RExec 추가 기능을 원하는대로 서브 클래 싱 할 수 있습니다.

그러나 이것이 학문적 추구에 더 가깝다면 여기에 좀 더 깊이 파고들 수있는 몇 가지 구피 접근법이 있습니다.

스크립트 예 :

./deep.py

print ' >> level 1'
execfile('deeper.py')
print ' << level 1'

./deeper.py

print '\t >> level 2'
exec("import sys; sys.path.append('/tmp'); import deepest")
print '\t << level 2'

/tmp/deepest.py

print '\t\t >> level 3'
print '\t\t\t I can see the earths core.'
print '\t\t << level 3'

./codespy.py

import sys, os

def overseer(frame, event, arg):
    print "loaded(%s)" % os.path.abspath(frame.f_code.co_filename)

sys.settrace(overseer)
execfile("deep.py")
sys.exit(0)

산출

loaded(/Users/synthesizerpatel/deep.py)
>> level 1
loaded(/Users/synthesizerpatel/deeper.py)
    >> level 2
loaded(/Users/synthesizerpatel/<string>)
loaded(/tmp/deepest.py)
        >> level 3
            I can see the earths core.
        << level 3
    << level 2
<< level 1

물론 이것은 리소스를 많이 사용하는 방법이므로 모든 코드를 추적해야합니다. 매우 효율적이지 않습니다. 그러나 둥지에 깊숙이 들어가도 계속 작동하기 때문에 새로운 접근법이라고 생각합니다. 'eval'을 무시할 수 없습니다. 할 있지만 execfile ()을 재정의합니다.

이 접근법은 '가져 오기'가 아닌 exec / exec 파일에만 적용됩니다. 더 높은 수준의 '모듈'로드 후킹의 경우 sys.path_hooks 를 사용할 수 있습니다. (PyMOTW의 쓰기 제공) .

그게 내가 머리 꼭대기에서 벗어난 전부입니다.


2

여기에 지금까지 게시 된 모든 솔루션보다 여전히 나은 부분 솔루션이 있습니다.

import sys, os, os.path, inspect

#os.chdir("..")

if '__file__' not in locals():
    __file__ = inspect.getframeinfo(inspect.currentframe())[0]

print os.path.dirname(os.path.abspath(__file__))

이제는 모든 호출이 작동하지만 누군가 chdir()현재 디렉토리를 변경하는 데 사용 하면 실패합니다.

노트:

  • sys.argv[0]작동하지 않을 것입니다 -c. 스크립트를 실행하면python -c "execfile('path-tester.py')"
  • https://gist.github.com/1385555 에서 완전한 테스트를 게시했으며 이를 개선 할 수 있습니다.

1

대부분의 경우 작동합니다.

import os,sys
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))

5
이 솔루션은 현재 디렉토리를 사용하며 해당 솔루션이 실패 할 것이라는 질문에 명시 적으로 명시되어 있습니다.
skyking

1

희망적으로 이것은 도움이됩니다 :-어디에서나 스크립트 / 모듈을 실행하면 스크립트 __file__의 위치를 ​​나타내는 모듈 변수 인 변수 에 액세스 할 수 있습니다 .

인터프리터를 사용하는 경우 반면에, 당신은 당신의 이름을 얻을 것이다 그 변수에 대한 액세스 권한이없는 NameErroros.getcwd() 당신이 다른 곳에서 파일을 실행하는 경우 당신에게 잘못된 디렉토리를 줄 것이다.

솔루션은 모든 경우에 원하는 것을 제공합니다.

from inspect import getsourcefile
from os.path import abspath
abspath(getsourcefile(lambda:0))

나는 그것을 철저히 테스트하지는 않았지만 내 문제를 해결했습니다.


이것은 디렉토리가 아닌 파일을 줄 것입니다
Shital Shah
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.