파이썬의 상대 경로


245

코드베이스의 몇 가지 템플릿 파일을 현재 디렉토리로 복사하는 간단한 도우미 스크립트를 작성 중입니다. 그러나 템플릿이 저장된 디렉토리의 절대 경로는 없습니다. 스크립트에서 상대 경로가 있지만 스크립트를 호출하면 현재 작업 디렉토리에 상대적인 경로로 처리합니다. 이 상대 URL이 대신 스크립트의 위치에서 오도록 지정하는 방법이 있습니까?


답변:


325

스크립트가있는 파일에서 다음과 같은 작업을 수행하려고합니다.

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

이것은 당신이 찾고있는 파일의 절대 경로를 줄 것입니다. setuptools를 사용하는 경우 패키지 자원 API를 대신 사용해야 합니다.

업데이트 : 여기에 주석에 응답하여 코드 샘플을 붙여 넣을 수 있습니다. :-)

__file__항상 사용할 수 있는 것은 아니라고 생각하는 것이 맞 습니까 (예 : 파일을 가져 오는 대신 직접 실행하는 경우)?

__main__파일을 직접 실행한다고 언급 할 때 스크립트 를 의미한다고 가정합니다 . 그렇다면 내 시스템 (OS X 10.5.7의 Python 2.5.1)에서는 그렇지 않은 것 같습니다.

#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py

그러나 __file__C 확장에 몇 가지 단점이 있다는 것을 알고 있습니다. 예를 들어, Mac에서이 작업을 수행 할 수 있습니다.

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

그러나 이것은 내 Windows 컴퓨터에서 예외를 발생시킵니다.


1
파일을 항상 사용할 수있는 것은 아니라고 생각하는 것이 맞 습니까 (예 : 파일을 가져 오는 대신 직접 실행하는 경우)?
Stephen Edmonds

@Stephen Edmonds 가져 오기보다는 실행하는 파일을 사용하고 있으며 훌륭하게 작동합니다.
baudtack 2016 년

22
이식성을 위해 어디에서나 os.path.join을 사용해야합니다.filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')
ford

22
os.path.dirname(__file__)빈 문자열을 줄 수 있습니다. os.path.dirname(os.path.abspath(__file__))대신 사용하십시오
Dmitry Trofimov

14
사소한 것이지만 dir은 내장되어 있기 때문에 dir을 변수 이름으로 사용하지 마십시오.
David

63

필요합니다 os.path.realpath(아래 샘플은 상위 디렉토리를 경로에 추가합니다)

import sys,os
sys.path.append(os.path.realpath('..'))

2
os.path.dirname(__file__)빈 줄을 줬어 이것은 완벽하게 작동했습니다.
Darragh Enright

3
이것은 스크립트의 위치가 아니라 스크립트가 실행되는 디렉토리의 부모를 제공하는 것으로 보입니다.
Coquelicot

10
os.path.realpath('..')현재 작업 디렉토리의 상위 디렉토리를 제공합니다 . 그것은 일반적으로 당신이 원하는 것이 아닙니다 .
Martijn Pieters

1
@DarraghEnright : Python-script-to-exe 패키징 환경에서만 발생합니다. 현재 작업 디렉토리에 의존하는 것이 드문 예외 중 하나입니다.
Martijn Pieters

52

허용 된 답변에서 언급했듯이

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')

그냥 추가하고 싶습니다

후자의 문자열은 백 슬래시로 시작할 수 없습니다. 실제로 어떤 문자열도 백 슬래시를 포함해서는 안됩니다

다음과 같아야합니다

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')

경우에 따라 허용 된 답변이 잘못 될 수 있습니다. 자세한 내용은 링크를 참조하십시오


4
os.path.joinOS 별 구분 기호와 결합 하여 사용하는 것이 좋습니다.
Farshid T

'/relative/path...'상대 경로가 아닙니다. 의도적인가요?
steveire

의 답변이에 올바른 상대 경로를 사용하도록 수정되었으므로이 답변은 이제 구식입니다 os.path.join(). 남은 것은 경로 구분자를 하드 코딩하는 것보다 각 경로 요소마다 별도의 문자열을 사용하는 것입니다.
Martijn Pieters

@MartijnPieters 그렇습니다. 최고의 답변은이 부분과 일치하도록 편집되었지만 별도의 문자열은 기본 설정이 아닙니다. 이와 같이 스팅을 분리하면 os 독립적입니다.
jshrimp29

26

이제 2018 년이며 Python은 이미 __future__오래 전에 진화했습니다 . 어떻게 놀라운 사용에 대한 pathlib작업을 수행하기 위해 파이썬 3.4와 함께 오는 대신에 어려움을 겪고 os, os.path, glob, shutil, 등

따라서 여기에 3 개의 경로가 있습니다 (아마도 복제 됨).

  • mod_path: 간단한 도우미 스크립트 의 경로입니다.
  • src_path: 복사 대기중인 두 개의 템플릿 파일 이 들어 있습니다.
  • cwd: 현재 디렉토리 , 해당 템플리트 파일의 대상

그리고 문제는 : 우리는없는 의 전체 경로를 src_path만 알고 그것의 상대 경로 받는 사람을 mod_path.

이제이 놀라운 문제를 해결해 보자 pathlib.

# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path

# `cwd`: current directory is straightforward
cwd = Path.cwd()

# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent

# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()

앞으로는 그렇게 간단합니다. :디


또한 다음을 사용하여 템플릿 파일을 선택하고 확인하고 복사 / 이동할 수 있습니다 pathlib.

if src_path != cwd:
    # When we have different types of files in the `src_path`
    for template_path in src_path.glob('*.ini'):
        fname = template_path.name
        target = cwd / fname
        if not target.exists():
            # This is the COPY action
            with target.open(mode='wb') as fd:
                fd.write(template_path.read_bytes())
            # If we want MOVE action, we could use:
            # template_path.replace(target)

14

내 코드를 고려하십시오.

import os


def readFile(filename):
    filehandle = open(filename)
    print filehandle.read()
    filehandle.close()



fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir

#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)

#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)

#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)

#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)

Windows에서 이것을 실행할 때 오류가 발생합니다. FileNotFoundError : [Errno 2] 해당 파일이나 디렉토리가 없습니다 : '<path>'여기서 <path>에는 올바른 경로 세그먼트가 있지만 구분 기호로 \\를 사용합니다.
lonstar

11

sys.path 참조 프로그램 시작시 초기화 된 대로이 목록의 첫 번째 항목 인 path [0]은 Python 인터프리터를 호출하는 데 사용 된 스크립트가 포함 된 디렉토리입니다.

이 경로를 상대 경로적용 할 루트 폴더로 사용하십시오.

>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'

3
반드시 그런 것은 아닙니다. 일반적으로 sys.path [0]은 빈 문자열 또는 점으로, 현재 디렉토리의 상대 경로입니다. 현재 디렉토리를 원하면 os.getcwd를 사용하십시오.
Jason Baker

원래 포스터는 현재 작업 디렉토리가 상대 경로를 기반으로하는 잘못된 위치라고 언급했습니다. sys.path [0]이 항상 유효한 것은 아니라고 말하는 것이 맞습니다.
Tom Leys

아니요, sys.path[0]항상 상위 디렉토리로 설정되어 있지는 않습니다. 파이썬 코드로 호출 할 수 있습니다 -c또는 -m또는 지점이있는 임베디드 통역을 통해 sys.path[0]모두 뭔가 다른 설정됩니다.
Martijn Pieters

6

사용하는 대신

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

허용 된 답변에서와 같이 사용하는 것이 더 강력합니다.

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

__file__을 사용하면 모듈이로드 된 파일을 반환하므로 파일에서로드 된 경우 스크립트가있는 파일을 다른 곳에서 호출하면 반환 된 디렉토리가 올바르지 않습니다.

이 답변은 https://stackoverflow.com/a/31867043/5542253https://stackoverflow.com/a/50502/5542253에 대한 자세한 정보를 제공합니다.


5
inspect.stack()호출 하는 데 비싼 기능입니다. 모든 스택 프레임에 대한 정보를 검색 한 다음 버리고 최상위 프레임 만 가져옵니다. 기본적으로 inspect.getfile()모듈 객체를 호출 합니다 module.__file__. 을 사용하는 것이 훨씬 낫습니다 __file__.
Martijn Pieters

4

안녕하십니까 우선 os.path.abspath (path)os.path.relpath (path) 함수를 이해해야합니다.

간단히 말해서 os.path.abspath (path)절대 경로에 대한 상대 경로 를 만듭니다. . 제공된 경로 자체가 절대 경로이면 함수는 동일한 경로를 반환합니다.

비슷하게 os.path.relpath (path)상대 경로에 대한 절대 경로 를 만듭니다 . 제공된 경로 자체가 상대 경로이면 함수는 동일한 경로를 반환합니다.

아래 예제는 위의 개념을 올바르게 이해하도록 할 수 있습니다 .

파이썬 스크립트로 처리 할 입력 파일 목록이 들어있는 input_file_list.txt 파일이 있다고 가정하십시오 .

D : \ conc \ input1.dic

D : \ conc \ input2.dic

D : \ Copyioconc \ input_file_list.txt

위의 폴더 구조 를 보면 copy_conc 폴더 에 input_file_list.txt 가 있고 파이썬 스크립트로 처리 할 파일은 conc에 있습니다 폴더에 있습니다

그러나 input_file_list.txt 파일의 내용은 다음과 같습니다.

.. \ conc \ input1.dic

.. \ conc \ input2.dic

그리고 내 파이썬 스크립트는 D : 드라이브에 있습니다.

그리고에서 제공하는 상대 경로 input_file_list.txt 파일의 경로를 기준으로 input_file_list.txt 파일.

따라서 파이썬 스크립트가 현재 작업 디렉토리를 실행할 때 ( 경로를 얻으려면 os.getcwd () 사용 )

내 상대 경로는 input_file_list.txt , 즉 "D : \ Copyofconc"상대적이므로 현재 작업 디렉토리를 "D : \ Copyofconc" 로 변경해야합니다 .

따라서 os.chdir ( 'D : \ Copyofconc') 을 사용해야 하므로 현재 작업 디렉토리는 "D : \ Copyofconc" 입니다.

이제 input1.dicinput2.dic 파일을 얻으려면 ".. \ conc \ input1.dic"줄을 읽은 다음 명령을 사용해야합니다.

input1_path = os.path.abspath ( '.. \ conc \ input1.dic') (상대 경로를 절대 경로로 변경합니다. 현재 작업 디렉토리는 "D : \ Copyofconc", ". \ conc \ input1 파일입니다. dic "은"D : \ Copyofconc "와 관련하여 액세스해야합니다.)

따라서 input1_path 는 "D : \ conc \ input1.dic"입니다.


4

이 코드는 기본 스크립트의 절대 경로를 반환합니다.

import os
def whereAmI():
    return os.path.dirname(os.path.realpath(__import__("__main__").__file__))

이것은 모듈에서도 작동합니다.


다시 가져 오는 대신을 사용 sys.modules['__main__'].__file__합니다.
Martijn Pieters

3

나를 위해 일하는 대안 :

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

0

나를 위해 일한 것은을 사용하고 sys.path.insert있습니다. 그런 다음 이동해야 할 디렉토리를 지정했습니다. 예를 들어 방금 하나의 디렉토리로 올라 가야했습니다.

import sys
sys.path.insert(0, '../')

1
이것은 현재 작업 디렉토리에 의존하며, 실제로 원하는 것과 크게 다를 수 있습니다.
Martijn Pieters

-2

이것이 이전 버전 중 일부에 적용되는지 확실하지 않지만 Python 3.3에는 기본 상대 경로 지원이 있다고 생각합니다.

예를 들어 다음 코드는 python 스크립트와 동일한 폴더에 텍스트 파일을 작성해야합니다.

open("text_file_name.txt", "w+t")

(상대 경로 인 경우 처음에 앞으로 또는 백 슬래시가 없어야합니다.)


OP가 요구하는 것이 아닌 CWD에서 작동합니다. 스크립트 위치에서 작업하고 싶습니다.
Samy Bencherif
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.