Bir ambalaj başlangıcı:
Kaynak dosyalarını okuma konusunda endişelenmeden önce, ilk adım, veri dosyalarının ilk etapta dağıtımınıza paketlendiğinden emin olmaktır - bunları doğrudan kaynak ağacından okumak kolaydır, ancak önemli olan şey yapmaktır. bu kaynak dosyalarına kurulu bir paket içindeki koddan erişilebildiğinden emin olun .
Bir alt dizinin içine veri dosyaları koyarak böyle Yapı projenizin içinde paketinin:
.
├── package
│ ├── __init__.py
│ ├── templates
│ │ └── temp_file
│ ├── mymodule1.py
│ └── mymodule2.py
├── README.rst
├── MANIFEST.in
└── setup.py
Sen geçmelidir include_package_data=True
içinde setup()
çağrı. Manifest dosyası yalnızca setuptools / distutils kullanmak ve kaynak dağıtımları oluşturmak istiyorsanız gereklidir. templates/temp_file
Bu örnek proje yapısının paketlendiğinden emin olmak için , manifest dosyasına şuna benzer bir satır ekleyin:
recursive-include package *
Tarihsel temel not: Varsayılan olarak paket veri dosyalarını içerecek olan flit, şiir gibi modern derleme arka uçları için bir bildirim dosyası kullanmak gerekmez . Yani, kullanıyorsanız pyproject.toml
ve bir setup.py
dosyanız yoksa, ilgili her şeyi göz ardı edebilirsiniz MANIFEST.in
.
Şimdi, ambalajı yoldan çıkararak, okuma kısmına ...
Öneri:
Standart kitaplık pkgutil
API'lerini kullanın . Kitaplık kodunda şöyle görünecek:
# within package/mymodule1.py, for example
import pkgutil
data = pkgutil.get_data(__name__, "templates/temp_file")
Fermuarlı çalışır. Python 2 ve Python 3 üzerinde çalışır. Üçüncü taraf bağımlılıkları gerektirmez. Herhangi bir dezavantajın gerçekten farkında değilim (eğer öyleyseniz, lütfen cevaba yorum yapın).
Kaçınmanın kötü yolları:
Kötü yol 1: Bir kaynak dosyadan göreli yolları kullanmak
Bu şu anda kabul edilen cevaptır. En iyi ihtimalle şuna benzer:
from pathlib import Path
resource_path = Path(__file__).parent / "templates"
data = resource_path.joinpath("temp_file").read_bytes()
Bunun derdi ne? Kullanılabilir dosyalarınız ve alt dizinleriniz olduğu varsayımı doğru değildir. Bu yaklaşım, bir zip veya bir tekerlek içinde paketlenmiş kod çalıştırılırken işe yaramaz ve paketinizin bir dosya sistemine çıkarılıp çıkarılmayacağı tamamen kullanıcının kontrolü dışında olabilir.
Kötü yol 2: pkg_resources API'lerini kullanma
Bu, en çok oylanan cevapta açıklanmıştır. Şuna benzer:
from pkg_resources import resource_string
data = resource_string(__name__, "templates/temp_file")
Bunun derdi ne? Bir ekleyen çalışma zamanı bağımlılığı setuptools tercihen bir olmalı, yüklemek sadece zaman bağımlılığı. pkg_resources
Kod, yalnızca kendi paket kaynaklarınızla ilgilenmiş olsanız bile , tüm kurulu paketlerin bir çalışma kümesini oluşturduğundan, içe aktarma ve kullanma gerçekten yavaşlayabilir . Bu, yükleme sırasında önemli bir sorun değil (yükleme bir kez kapalı olduğundan), ancak çalışma zamanında çirkin.
Kötü yol 3: importlib.resources API'lerini kullanma
Bu, şu anda en çok oy alan cevapta öneridir. Yeni bir standart kitaplık ekidir ( Python 3.7'de yeni ). Şöyle görünüyor:
from importlib.resources import read_binary
data = read_binary("package.templates", "temp_file")
Bunun derdi ne? Maalesef işe yaramıyor ... henüz. Bu hala tamamlanmamış bir API'dir; kullanmak , veri dosyalarının bir alt dizin yerine bir alt paket içinde yer alması için importlib.resources
boş bir dosya eklemenizi gerektirir templates/__init__.py
. Ayrıca, package/templates
alt dizini package.templates
kendi başına içe aktarılabilir bir alt paket olarak ortaya çıkaracaktır . Bu büyük bir sorun değilse ve sizi rahatsız etmiyorsa, devam edip __init__.py
dosyayı oraya ekleyebilir ve kaynaklara erişmek için içe aktarma sistemini kullanabilirsiniz. Bununla birlikte, oradayken, bunun my_resources.py
yerine bir dosyaya dönüştürebilir ve modülde sadece bazı baytlar veya dize değişkenleri tanımlayabilir, ardından bunları Python koduna aktarabilirsiniz. Her iki şekilde de burada ağır işi yapan ithalat sistemi.
Onur sözü: daha yeni importlib_resources API'leri kullanma
Bu henüz importlib_resources
başka bir yanıtta belirtilmemiştir, ancak Python 3.7+ importlib.resources
kodunun basit bir arka planından daha fazlasıdır . Bunun gibi kullanabileceğiniz geçiş yapılabilir API'lara sahiptir:
import importlib_resources
my_resources = importlib_resources.files("package")
data = (my_resources / "templates" / "temp_file").read_bytes()
Bu Python 2 ve 3 üzerinde çalışır, zip şeklinde çalışır ve __init__.py
kaynak alt dizinlerine sahte dosyaların eklenmesini gerektirmez . Görebildiğim tek dezavantajı pkgutil
, bu yeni API'lerin henüz stdlib'e ulaşmamış olması, dolayısıyla hala bir üçüncü taraf bağımlılığı var. Python 3.9'da daha yeni API'ler importlib_resources
stdlib'e ulaşmalıdır importlib.resources
.
Örnek proje:
Github'da örnek bir proje oluşturdum ve yukarıda tartışılan beş yaklaşımı da gösteren PyPI'ye yükledim . Şununla deneyin:
$ pip install resources-example
$ resources-example
Daha fazla bilgi için https://github.com/wimglenn/resources-example adresine bakın .