Python 패키지 내부에서 (정적) 파일을 읽는 방법은 무엇입니까?
파이썬 패키지 안에있는 파일을 어떻게 읽을 수 있는지 말해 줄 수 있습니까?
내 상황
내가로드하는 패키지에는 프로그램 내에서로드하려는 여러 템플릿 (문자열로 사용되는 텍스트 파일)이 있습니다. 그러나 그러한 파일의 경로를 어떻게 지정합니까?
다음에서 파일을 읽고 싶다고 상상해보십시오.
package\templates\temp_file
어떤 종류의 경로 조작? 패키지 기본 경로 추적?
[2016-06-15 추가 : 분명히 이것은 모든 상황에서 작동하지 않습니다. 다른 답변을 참조하십시오]
import os, mypackage
template = os.path.join(mypackage.__path__[0], 'templates', 'temp_file')
TLDR; 아래 방법 2 번에 설명 된대로 표준 라이브러리의 importlib.resources
모듈 을 사용하십시오 .
전통 pkg_resources
에서이setuptools
로 인해 더 이상 사용하지 않는 것이 좋습니다 성능상의 이유로 .
기존 코드를 이식 할 때 새 방법과의 차이점을 설명하기 위해 먼저 나열된 기존 코드를 유지했습니다 ( 여기 에서도 이식 설명 ).
템플릿이 모듈 패키지 내부에 중첩 된 폴더에 있다고 가정 해 보겠습니다.
<your-package>
+--<module-asking-the-file>
+--templates/
+--temp_file <-- We want this file.
참고 1 : 확실히
__file__
속성을 조작 해서는 안됩니다 (예 : zip에서 제공 될 때 코드가 손상됨).2 주 : 이 패키지를 빌드하는 경우로 데이터 파일을 declatre 기억
package_data
또는data_files
당신을에서setup.py
.
1) pkg_resources
from setuptools
(느림) 사용
setuptools 배포판의 pkg_resources
패키지를 사용할 수 있지만 성능면 에서 비용이 발생 합니다 .
import pkg_resources
# Could be any dot-separated package/module name or a "Requirement"
resource_package = __name__
resource_path = '/'.join(('templates', 'temp_file')) # Do not use os.path.join()
template = pkg_resources.resource_string(resource_package, resource_path)
# or for a file-like stream:
template = pkg_resources.resource_stream(resource_package, resource_path)
팁 :
배포판이 압축되어 있어도 데이터를 읽으므로
zip_safe=True
에서 설정setup.py
하거나 python-3.5 에서 오랫동안 기다려온zipapp
패커 를 사용하여 자체 포함 된 배포판을 만들 수 있습니다.
setuptools
런타임 요구 사항 에 추가하는 것을 잊지 마십시오 (예 : install_requires`).
... 그리고 Setuptools / pkg_resources
문서 에 따르면 다음을 사용해서는 안됩니다 os.path.join
.
기본 리소스 액세스
리소스 이름은
/
경로로 구분되어야하며 절대적 (즉, 선행 없음/
)이거나 "..
" 와 같은 상대 이름을 포함 할 수 없습니다 . 마십시오 하지 사용os.path
은 그대로, 자원 경로를 조작하는 루틴을 하지 파일 시스템 경로.
2) Python> = 3.7 또는 백 포트 importlib_resources
라이브러리 사용
위의 보다 효율적인 표준 라이브러리 importlib.resources
모듈 을 사용하십시오 setuptools
.
try:
import importlib.resources as pkg_resources
except ImportError:
# Try backported to PY<37 `importlib_resources`.
import importlib_resources as pkg_resources
from . import templates # relative-import the *package* containing the templates
template = pkg_resources.read_text(templates, 'temp_file')
# or for a file-like stream:
template = pkg_resources.open_text(templates, 'temp_file')
주의:
기능에 관하여
read_text(package, resource)
:
- 는
package
문자열이나 모듈이 될 수 있습니다.- 는
resource
더 이상 경로,하지만 기존 패키지에서 열 수있는 자원, 단지 파일 이름이 아니다; 경로 구분 기호를 포함 할 수 없으며 하위 리소스가 없을 수도 있습니다 (즉, 디렉토리가 될 수 없음).
질문에서 묻는 예의 경우 이제 다음을 수행해야합니다.
- (가) 만들어
<your_package>/templates/
빈 생성하여, 적절한 패키지로__init__.py
거기에 파일을 - 이제 우리는 간단한 (아마도 상대적인)
import
문을 사용할 수 있습니다 (더 이상 패키지 / 모듈 이름을 구문 분석하지 않음). resource_name = "temp_file"
(경로 없음)을 요청하십시오 .
팁 :
- 때 상황이 재미가 될 실제 파일 이름이 함께 요구되는
path()
지금 상황에 관리자가 일시적으로 생성 된 파일 (읽기에 사용되기 때문에, 이 ).- 와, 조건부 이전의 파이를 들어, 백 포트 라이브러리 추가
install_requires=[" importlib_resources ; python_version<'3.7'"]
(확인 이 당신이 프로젝트를 패키징하는 경우setuptools<36.2.1
).- 기존 방법에서 마이그레이션 한 경우 런타임 요구 사항
setuptools
에서 라이브러리 를 제거해야합니다 .zip_safe=True
에서 설정할 수도 있습니다setup.py
.
이 구조가있는 경우
lidtk
├── bin
│ └── lidtk
├── lidtk
│ ├── analysis
│ │ ├── char_distribution.py
│ │ └── create_cm.py
│ ├── classifiers
│ │ ├── char_dist_metric_train_test.py
│ │ ├── char_features.py
│ │ ├── cld2
│ │ │ ├── cld2_preds.txt
│ │ │ └── cld2wili.py
│ │ ├── get_cld2.py
│ │ ├── text_cat
│ │ │ ├── __init__.py
│ │ │ ├── REAMDE.md <---------- say you want to get this
│ │ │ └── textcat_ngram.py
│ │ └── tfidf_features.py
│ ├── data
│ │ ├── __init__.py
│ │ ├── create_ml_dataset.py
│ │ ├── download_documents.py
│ │ ├── language_utils.py
│ │ ├── pickle_to_txt.py
│ │ └── wili.py
│ ├── __init__.py
│ ├── get_predictions.py
│ ├── languages.csv
│ └── utils.py
├── README.md
├── setup.cfg
└── setup.py
이 코드가 필요합니다.
import pkg_resources
# __name__ in case you're within the package
# - otherwise it would be 'lidtk' in this example as it is the package name
path = 'classifiers/text_cat/REAMDE.md' # always use slash
filepath = pkg_resources.resource_filename(__name__, path)
"항상 슬래시 사용"부분에 대해 잘 모르겠습니다. 그것은에서 올 수 있습니다setuptools
또한 경로를 사용하는 경우 Windows를 사용하는 경우에도 경로 구분 기호로 슬래시 (/)를 사용해야합니다. Setuptools는 빌드시 슬래시를 적절한 플랫폼 별 구분 기호로 자동 변환합니다.
문서가 어디에 있는지 궁금한 경우 :
David Beazley와 Brian K. Jones가 답을 제공하는 Python Cookbook, Third Edition의 "10.8. 패키지 내의 데이터 파일 읽기"의 내용.
여기로 가져 오겠습니다.
다음과 같이 구성된 파일이 포함 된 패키지가 있다고 가정합니다.
mypackage/
__init__.py
somedata.dat
spam.py
Now suppose the file spam.py wants to read the contents of the file somedata.dat. To do it, use the following code:
import pkgutil
data = pkgutil.get_data(__package__, 'somedata.dat')
The resulting variable data will be a byte string containing the raw contents of the file.
The first argument to get_data() is a string containing the package name. You can either supply it directly or use a special variable, such as __package__
. The second argument is the relative name of the file within the package. If necessary, you can navigate into different directories using standard Unix filename conventions as long as the final directory is still located within the package.
In this way, the package can installed as directory, .zip or .egg.
Every python module in your package has a __file__
attribute
You can use it as:
import os
from mypackage
templates_dir = os.path.join(os.path.dirname(mypackage.__file__), 'templates')
template_file = os.path.join(templates_dir, 'template.txt')
For egg resources see: http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resources
assuming you are using an egg file; not extracted:
I "solved" this in a recent project, by using a postinstall script, that extracts my templates from the egg (zip file) to the proper directory in the filesystem. It was the quickest, most reliable solution I found, since working with __path__[0]
can go wrong sometimes (i don't recall the name, but i cam across at least one library, that added something in front of that list!).
Also egg files are usually extracted on the fly to a temporary location called the "egg cache". You can change that location using an environment variable, either before starting your script or even later, eg.
os.environ['PYTHON_EGG_CACHE'] = path
However there is pkg_resources that might do the job properly.
You should be able to import portions of your package's name space with something like:
from my_package import my_stuff
... you should not need to specify anything that looks like a filename if this is a properly constructed Python package (that's normally abstracted away).
참고URL : https://stackoverflow.com/questions/6028000/how-to-read-a-static-file-from-inside-a-python-package
'Program Tip' 카테고리의 다른 글
django의 auth_user.username이 varchar (75)가 될 수 있습니까? (0) | 2020.11.17 |
---|---|
Rails 3 : 새 중첩 리소스를 만드는 방법은 무엇입니까? (0) | 2020.11.17 |
변수에서 대소 문자 구분을 무시하는 Windows 배치 명령 (0) | 2020.11.17 |
Blob에 저장된 미디어 파일의 콘텐츠 유형 설정 (0) | 2020.11.17 |
파일이없는 경우 파일 만들기 (0) | 2020.11.17 |