코드 리포지토리 작업시 리소스의 상대 경로를 참조하는 방법


188

우리는 Windows와 Linux 모두에 배포되는 코드 리포지토리를 사용하고 있으며 때로는 다른 디렉토리에 있습니다. 프로젝트 내부의 모듈 중 하나가 프로젝트의 비 Python 리소스 (CSV 파일 등) 중 하나를 어떻게 참조해야합니까?

우리가 다음과 같은 일을하면 :

thefile=open('test.csv')

또는:

thefile=open('../somedirectory/test.csv')

스크립트가 하나의 특정 디렉토리 또는 디렉토리의 서브 세트에서 실행될 때만 작동합니다.

내가하고 싶은 일은 다음과 같습니다.

path=getBasePathOfProject()+'/somedirectory/test.csv'
thefile=open(path)

가능합니까?

답변:


255

현재 파일 경로에 상대적인 파일 이름을 사용하십시오. './my_file'의 예 :

fn = os.path.join(os.path.dirname(__file__), 'my_file')

Python 3.4 이상 에서는 pathlib 를 사용할 수도 있습니다 .

fn = pathlib.Path(__file__).parent / 'my_file'

3
이 솔루션은 리소스가 파이썬 파일의 동일한 디렉토리 또는 그 하위 디렉토리에있는 경우에만 작동한다고 생각합니다. 다음과 같은 트리 구조가있을 때 당신은 그것을 해결하려면 어떻게 여기 여기 / Project_Root_dir / python_files_dir / 좀 더 하위 디렉토리 py_file.py / 자원 / 일부 하위 디렉토리 resource_file.csv
olamundo

1
죄송합니다, 마지막 메시지에서 파일 트리가 깨졌습니다 ... 두 번째 시도 : /Project_Root_dir/python_files_dir/some_subdirs/py_file.py에 파일이 있고 /Project_Root_dir/resources/some_subdirs/resource_file.csv에 파일이 있습니다.
olamundo

28
join (foo, '..')을 사용하여 상위 디렉토리로 이동할 수 있어야합니다. 따라서 / root / python_files / module / myfile에서 os.path.join (os.path.dirname ( __file__), '..', '..', 'resources')을 사용하십시오.
c089

7
os.pardir'..'POSIX와 Windows 모두에서 동일하지만 둘 보다 약간 낫습니다 .
davidchambers

4
@ cedbeu : 그것은 내가 본 모든 시스템에서 동일하며 오늘 모든 시스템 파이썬이 실행된다고 생각합니다 (여기서 잘못하면 수정하십시오). 그러나 나중에 다른 경로 구분 기호를 사용하여 파이썬을 시스템에 이식하고 코드를 준비하려면 os.pardir이 더 이식성이 뛰어납니다. 모든 프로그래머, 심지어 파이썬을 읽지 않은 사람조차도 ".."의 의미를 알고 있지만 "os.pardir"은 문서에서 개인적으로 찾아봐야 할 간접적 인 수준입니다. ' d ".."에 붙어 있습니다.
c089

40

설정 도구를 사용하거나 배포 (setup.py 설치)하는 경우 이러한 패키지 된 리소스에 액세스하는 "올바른"방법은 package_resources를 사용하는 것 같습니다.

귀하의 경우 예는

import pkg_resources
my_data = pkg_resources.resource_string(__name__, "foo.dat")

물론 리소스를 읽고 이진 데이터를 읽는 것은 my_data의 값입니다.

파일 이름이 필요하면 사용할 수도 있습니다.

resource_filename(package_or_requirement, resource_name)

예:

resource_filename("MyPackage","foo.dat")

장점은 계란과 같은 아카이브 배포 일지라도 작동하도록 보장한다는 것입니다.

http://packages.python.org/distribute/pkg_resources.html#resourcemanager-api를 참조 하십시오.


3
나는 이것이 오래된 대답이라는 것을 알고 있으며, 선호하는 방법은 pkg_resources를 사용하는 것입니다 (/ 아마?) 압축 된 계란이 사라지면 __file__좋은 옛날처럼 사용하는 데 해가 있습니까?
Pykler

1
이것은 확실한 접근법입니다. 계란이 런타임에 내장되는 경우에도 계란 규칙 멀리가는 경우, setuptools에는 많은 사람들이 여전히 자식의 repos에 대한 deps를 설치하지 않습니다
deepelement

18

Python에서 경로는 현재 작업 디렉토리에 상대적 이며, 대부분의 경우 프로그램을 실행하는 디렉토리입니다. 현재 작업 디렉토리는 현재 모듈 파일에 상대 경로를 사용하므로 항상 나쁜 선택이다, 아주 가능성이없는 모듈 파일의 디렉토리와 동일하다.

절대 경로를 사용하는 것이 가장 좋습니다.

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')

15

나는 종종 이와 비슷한 것을 사용합니다 :

import os
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir'))

# if you have more paths to set, you might want to shorten this as
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x))
DATA_DIR = here('datadir') 

pathjoin = os.path.join
# ...
# later in script
for fn in os.listdir(DATA_DIR):
    f = open(pathjoin(DATA_DIR, fn))
    # ...

변수

__file__

는 코드를 작성하는 스크립트의 파일 이름을 보유하므로 스크립트에 상대적인 경로를 만들 수 있지만 여전히 절대 경로로 작성됩니다. 몇 가지 이유로 꽤 잘 작동합니다.

  • 경로는 절대적이지만 여전히 상대적
  • 프로젝트는 여전히 상대 컨테이너에 배포 할 수 있습니다

그러나 플랫폼 호환성에주의해야합니다. Windows의 os.pathsep는 UNIX와 다릅니다.


5
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

또한를 cwd사용하여 정규화하려고합니다 os.path.abspath(os.getcwd()). 자세한 내용은 여기를 참조하십시오 .


3
cwd그러나 모듈의 경로 인 유스 케이스는 거의 없다
cedbeu

스크립트에서 설정 한 동일한 디렉토리 (또는 작업 디렉토리)에서만 패키지 내부에서 작동하지 않습니다.
alexandra

사용자가 다른 디렉토리의 절대 경로를 사용하여 프로그램을 실행하면 작동하지 않습니다. 예 : python3 /usr/someone/test.py
sgrpwr

2

빌드 __file__변수를 사용할 수 있습니다 . 현재 파일의 경로를 포함합니다. 프로젝트 루트의 모듈에서 getBaseOfProject를 구현합니다. 거기에서 나는 경로의 일부를 얻고 그것을 __file__반환 할 것입니다. 이 방법은 프로젝트의 어느 곳에서나 사용할 수 있습니다.


0

나는 여기에 조금 넘어졌다. 일부 리소스 파일을 휠 파일로 패키징하고 액세스하려고했습니다. 매니페스트 파일을 사용하여 패키징을 수행했지만 하위 디렉토리가 아닌 한 pip install이 설치하지 않았습니다. 이 sceen 샷을 기대하면 도움이 될 것입니다

├── cnn_client
   ├── image_preprocessor.py
   ├── __init__.py
   ├── resources
      ├── mscoco_complete_label_map.pbtxt
      ├── retinanet_complete_label_map.pbtxt
      └── retinanet_label_map.py
   ├── tf_client.py

매니페스트

recursive-include cnn_client/resources *

표준 setup.py를 사용하여 웰을 생성했습니다. pip는 wheel 파일을 설치했습니다. 설치 후 리소스가 설치되어 있는지 확인하십시오. 그들은

ls /usr/local/lib/python2.7/dist-packages/cnn_client/resources

mscoco_complete_label_map.pbtxt
retinanet_complete_label_map.pbtxt 
 retinanet_label_map.py  

tfclient.py에서 이러한 파일에 액세스하십시오. ...에서

templates_dir = os.path.join(os.path.dirname(__file__), 'resources')
 file_path = os.path.join(templates_dir, \
            'mscoco_complete_label_map.pbtxt')
        s = open(file_path, 'r').read()

그리고 작동합니다.


-5

나는 이것에 대한 답을 알아내는 데 오랜 시간을 보냈지 만 마침내 그것을 얻었습니다 (실제로는 정말 간단합니다).

import sys
import os
sys.path.append(os.getcwd() + '/your/subfolder/of/choice')

# now import whatever other modules you want, both the standard ones,
# as the ones supplied in your subfolders

이것은 하위 폴더의 상대 경로를 파이썬이 볼 수있는 디렉토리에 추가합니다. 매우 빠르고 더럽지 만 매력처럼 작동합니다 :)


6
이것은 .py 파일과 동일한 디렉토리에서 Python 프로그램을 실행하는 경우에만 작동합니다. 이 경우 open('your/subfolder/of/choice')어쨌든 할 수 있습니다 .
Paul Fisher

4
OP는 코드가 Windows와 Linux 모두에서 작동해야한다고 언급했습니다. 그렇지 않습니다.
user183037
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.