[python] 패키지 서브 디렉토리의 데이터에 액세스

./data/하위 디렉토리 에서 데이터 파일을 열어야하는 모듈로 파이썬 패키지를 작성 중 입니다. 지금은 클래스와 함수에 하드 코딩 된 파일 경로가 있습니다. 하위 시스템이 사용자 시스템에 설치된 위치에 관계없이 하위 디렉토리에 액세스 할 수있는보다 강력한 코드를 작성하고 싶습니다.

나는 다양한 방법을 시도했지만 지금까지 나는 운이 없었습니다. 대부분의 “현재 디렉토리”명령은 모듈의 디렉토리가 아닌 시스템의 파이썬 인터프리터의 디렉토리를 반환하는 것으로 보입니다.

이것은 사소하고 일반적인 문제인 것 같습니다. 그러나 나는 그것을 알아낼 수없는 것 같습니다. 문제의 일부는 내 데이터 파일이 파일이 아니므로 .py가져 오기 기능 등을 사용할 수 없다는 것입니다.

어떤 제안?

현재 내 패키지 디렉토리는 다음과 같습니다.

/
__init__.py
module1.py
module2.py
data/
   data.txt

나는 액세스하려고하고 있어요 data.txt에서 module*.py!



답변

다음 __file__과 같이 패키지 경로를 얻는 데 사용할 수 있습니다 .

import os
this_dir, this_filename = os.path.split(__file__)
DATA_PATH = os.path.join(this_dir, "data", "data.txt")
print open(DATA_PATH).read()


답변

이를 수행하는 표준 방법은 setuptools 패키지 및 pkg_resources를 사용하는 것입니다.

다음 계층 구조에 따라 패키지를 배치하고이 링크에 따라 패키지 설정 파일이 데이터 리소스를 가리 키도록 구성 할 수 있습니다.

http://docs.python.org/distutils/setupscript.html#installing-package-data

그런 다음이 링크에 따라 pkg_resources를 사용하여 해당 파일을 다시 찾아 사용할 수 있습니다.

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/')
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db')


답변

오늘날 작동하는 솔루션을 제공합니다. 바퀴를 모두 재발 명하지 않으려면이 API를 사용하십시오.

실제 파일 시스템 파일 이름이 필요합니다. 압축 된 계란은 캐시 디렉토리로 추출됩니다.

from pkg_resources import resource_filename, Requirement

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

지정된 리소스에 대해 읽을 수있는 파일과 유사한 객체를 반환합니다. 실제 파일, StringIO 또는 유사한 객체 일 수 있습니다. 스트림은 리소스에있는 바이트가 그대로 읽히도록 “바이너리 모드”에 있습니다.

from pkg_resources import resource_stream, Requirement

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

pkg_resources를 사용한 패키지 발견 및 자원 액세스


답변

작동 하지 않는 코드를 자세히 설명하는 대답을 종종 지적하지는 않지만 예외라고 생각합니다. 파이썬 3.7 importlib.resources이이를 대체하기로했습니다 pkg_resources. 이름에 슬래시 가없는 패키지 내의 파일에 액세스하는 데 사용됩니다.

foo/
    __init__.py
    module1.py
    module2.py
    data/
       data.txt
    data2.txt

즉 , 예를 들어 data2.txt패키지 내부에 액세스 할 수 있습니다foo

importlib.resources.open_binary('foo', 'data2.txt')

그러나 그것은 예외로 실패 할 것입니다.

>>> importlib.resources.open_binary('foo', 'data/data.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/importlib/resources.py", line 87, in open_binary
    resource = _normalize_path(resource)
  File "/usr/lib/python3.7/importlib/resources.py", line 61, in _normalize_path
    raise ValueError('{!r} must be only a file name'.format(path))
ValueError: 'data/data2.txt' must be only a file name

이 배치 제외하고 수정할 수 없습니다 __init__.pydata패키지로 사용하여 다음과 :

importlib.resources.open_binary('foo.data', 'data.txt')

이 동작의 이유는 “디자인에 의한 것”입니다 . 그러나 디자인이 바뀔 수 있습니다


답변

전체 모듈의 이름이 필요합니다. 디렉토리 트리에는 세부 정보가 나와 있지 않습니다.

import pkg_resources
print(
    pkg_resources.resource_filename(__name__, 'data/data.txt')
)

특히 setuptools는 압축 된 데이터 파일과 이름 일치를 기반으로 파일을 확인하지 않는 것처럼 보이 data/므로 어떤 경우에도 접두사를 거의 포함시켜야합니다 . os.path.join('data', 'data.txt)대체 디렉토리 구분 기호가 필요한 경우 사용할 수 있습니다 . 일반적으로 하드 코딩 된 유닉스 스타일 디렉토리 구분 기호와의 호환성 문제는 없습니다.


답변

나는 대답을 찾아 냈다고 생각합니다.

data_path.py 모듈을 만들고 다음을 포함하는 다른 모듈로 가져옵니다.

data_path = os.path.join(os.path.dirname(__file__),'data')

그런 다음 모든 파일을

open(os.path.join(data_path,'filename'), <param>)


답변