Dalam Python, paket namespace memungkinkan Anda untuk menyebarkan kode Python di antara beberapa proyek. Ini berguna ketika Anda ingin merilis perpustakaan terkait sebagai unduhan terpisah. Misalnya, dengan direktori Package-1
dan Package-2
di PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
pengguna akhir dapat import namespace.module1
dan import namespace.module2
.
Apa cara terbaik untuk mendefinisikan paket namespace sehingga lebih dari satu produk Python dapat mendefinisikan modul di namespace itu?
python
namespaces
package
joeforker
sumber
sumber
Jawaban:
TL; DR:
Pada Python 3.3 Anda tidak perlu melakukan apa-apa, hanya saja jangan memasukkan apa pun
__init__.py
di direktori paket namespace Anda dan itu hanya akan berfungsi. Pada pra-3.3, pilihpkgutil.extend_path()
solusinyapkg_resources.declare_namespace()
, karena ini adalah bukti masa depan dan sudah kompatibel dengan paket namespace implisit.Python 3.3 memperkenalkan paket namespace implisit, lihat PEP 420 .
Ini berarti sekarang ada tiga jenis objek yang dapat dibuat oleh
import foo
:foo.py
filefoo
berisi__init__.py
filefoo
tanpa__init__.py
filePaket adalah modul juga, tapi di sini maksud saya "modul non-paket" ketika saya mengatakan "modul".
Pertama memindai
sys.path
modul atau paket reguler. Jika berhasil, ia berhenti mencari dan membuat dan menginisialisasi modul atau paket. Jika tidak menemukan modul atau paket reguler, tetapi ia menemukan setidaknya satu direktori, itu membuat dan menginisialisasi paket namespace.Modul dan paket reguler telah
__file__
diatur ke.py
file tempat mereka dibuat. Paket reguler dan namespace telah__path__
ditetapkan ke direktori atau direktori tempat mereka dibuat.Ketika Anda melakukannya
import foo.bar
, pencarian di atas terjadi terlebih dahulufoo
, kemudian jika sebuah paket ditemukan, pencarianbar
dilakukan denganfoo.__path__
sebagai jalur pencarian alih-alihsys.path
. Jikafoo.bar
ditemukan,foo
danfoo.bar
dibuat serta diinisialisasi.Jadi bagaimana paket reguler dan paket namespace tercampur? Biasanya tidak, tetapi
pkgutil
metode paket namespace eksplisit lama telah diperluas untuk menyertakan paket namespace implisit.Jika Anda memiliki paket reguler yang sudah ada yang memiliki
__init__.py
seperti ini:... perilaku lawas adalah menambahkan paket reguler lain di jalur yang dicari ke
__path__
. Namun dalam Python 3.3, ia juga menambahkan paket namespace.Jadi Anda dapat memiliki struktur direktori berikut:
... dan selama keduanya
__init__.py
memilikiextend_path
garis (danpath1
,path2
danpath3
ada di Andasys.path
)import package.foo
,import package.bar
danimport package.baz
semua akan bekerja.pkg_resources.declare_namespace(__name__)
belum diperbarui untuk menyertakan paket namespace implisit.sumber
namespace_packages
opsi ini? Dan__import__('pkg_resources').declare_namespace(__name__)
masalahnya?namespace_packages=['package']
disetup.py
?namespace_packages=['package']
, setup.py akan menambahkannamespace_packages.txt
dalam EGG-INFO. Masih tidak tahu dampaknya ...pkg_resources.declare_namespace
lebih dari itupkgutil.extend_path
adalah akan terus memonitorsys.path
. Dengan begitu, jika item baru ditambahkan kesys.path
setelah paket di namespace pertama kali dimuat maka paket di namespace di item jalur baru masih dapat dimuat. (Manfaat menggunakan__import__('pkg_resources')
lebih dari ituimport pkg_resources
adalah bahwa Anda tidak berakhirpkg_resources
terekspos sebagaimy_namespace_pkg.pkg_resources
.)sys.path
. Ketikasys.path
perubahan memeriksa apakah itu memengaruhi__path__
namespace mana pun, dan jika itu terjadi maka ia memperbarui__path__
properti tersebut.Ada modul standar, yang disebut pkgutil , yang dengannya Anda dapat 'menambahkan' modul ke namespace yang diberikan.
Dengan struktur direktori yang Anda berikan:
Anda harus meletakkan kedua baris di keduanya
Package-1/namespace/__init__.py
danPackage-2/namespace/__init__.py
(*):(* karena - kecuali Anda menyatakan ketergantungan di antara mereka - Anda tidak tahu yang mana yang akan dikenali lebih dulu - lihat PEP 420 untuk informasi lebih lanjut)
Seperti yang dikatakan dalam dokumentasi :
Mulai sekarang, Anda harus dapat mendistribusikan kedua paket secara mandiri.
sumber
__import__
dianggap gaya yang buruk dalam hal ini karena dapat dengan mudah diganti dengan pernyataan impor biasa. Lebih penting lagi, pkg_resources adalah pustaka non-standar. Itu datang dengan setuptools, jadi itu bukan masalah. Googling cepat mengungkapkan bahwa pkgutil diperkenalkan pada 2.5 dan pkg_resources mendahului itu. Namun demikian, pkgutil adalah solusi yang diakui secara resmi. pkg_resources penyertaan, pada kenyataannya, ditolak di PEP 365.Package-1/namespace/__init__.py
danPackage-2/namespace/__init__.py
asalkan kita tidak tahu paket Package mana yang didaftar pertama?Bagian ini harus cukup jelas.
Singkatnya, masukkan kode namespace
__init__.py
, perbaruisetup.py
untuk mendeklarasikan namespace, dan Anda bebas untuk pergi.sumber
Ini adalah pertanyaan lama, tetapi seseorang baru-baru ini berkomentar di blog saya bahwa postingan saya tentang paket namespace masih relevan, jadi saya pikir saya akan menautkannya di sini karena memberikan contoh praktis bagaimana membuatnya:
https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb
Itu tautan ke artikel ini untuk nyali utama dari apa yang terjadi:
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
The
__import__("pkg_resources").declare_namespace(__name__)
trick cukup banyak drive pengelolaan plugin di TiddlyWeb dan sejauh tampaknya akan bekerja keluar.sumber
Anda memiliki konsep namespace Python Anda kembali ke depan, tidak mungkin dalam python untuk meletakkan paket ke dalam modul. Paket berisi modul bukan sebaliknya.
Paket Python hanyalah sebuah folder yang berisi
__init__.py
file. Modul adalah file lain apa pun dalam suatu paket (atau langsung padaPYTHONPATH
) yang memiliki.py
ekstensi. Jadi, dalam contoh Anda, Anda memiliki dua paket tetapi tidak ada modul yang ditentukan. Jika Anda menganggap bahwa paket adalah folder sistem file dan modul adalah file maka Anda melihat mengapa paket berisi modul dan bukan sebaliknya.Jadi dalam contoh Anda dengan asumsi Package-1 dan Package-2 adalah folder pada sistem file yang telah Anda letakkan di jalur Python Anda dapat memiliki yang berikut ini:
Anda sekarang memiliki satu paket
namespace
dengan dua modulmodule1
danmodule2
. dan kecuali Anda memiliki alasan yang baik Anda mungkin harus meletakkan modul di folder dan hanya memiliki itu di jalur python seperti di bawah ini:sumber
zope.x
mana banyak paket terkait dirilis sebagai unduhan terpisah.