파이썬의 상대 경로


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/5542253 및 https://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.dic 및 input2.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.