Terkadang menjadi perlu untuk memisahkan beberapa paket yang terletak di namespace yang sama di sepanjang jalur fisik yang berbeda. Misalnya, jika Anda ingin dapat mentransfer tata letak plugin yang berbeda, memiliki kemampuan untuk kemudian menambahkannya tanpa mengendalikan lokasi mereka, dan pada saat yang sama, mengaksesnya melalui satu namespace.
Lembar cheat ini, yang lebih cocok untuk pemula, didedikasikan untuk ruang nama Python.
Mari kita lihat bagaimana hal ini dapat dilakukan dalam berbagai versi Python, karena walaupun Python2 tidak lagi didukung segera, banyak dari kita sekarang di antara dua kebakaran, dan ini hanyalah salah satu nuansa penting dalam transisi.

Pertimbangkan contoh ini:
Kami ingin mendapatkan struktur paket:
namespace1 package1 module1 package2 module2
Isi file Module1
print('package 1') var1 = 1
Isi file Module2
print('package 2') var2 = 2
Pada saat yang sama, paket didistribusikan dalam struktur folder berikut:
path1 namespace1 package1 module1 path2 namespace1 package2 module2
Misalkan path1 dan path2 telah ditambahkan ke sys.path. Kita perlu mengakses module1 dan module2:
from namespace1.package1 import module1 from namespace1.package2 import module2
Apa yang terjadi di
Python 3.7 ketika kode ini dieksekusi? Semuanya bekerja sangat baik:
package 1 package 2
Dengan PEP-420 di Python 3.3, dukungan untuk ruang nama implisit telah muncul. Selain itu, saat mengimpor paket dari py33, Anda tidak perlu membuat file __init__.py. Dan ketika mengimpor namespace, itu hanya _ dilarang_. Jika file __init__.py ada di satu atau kedua direktori dengan nama name1, kesalahan akan terjadi pada impor paket kedua.
ModuleNotFoundError: No module named 'namespace1.package2'
Dengan demikian, keberadaan orang dalam secara eksplisit menentukan paket, dan paket tidak dapat digabungkan, itu adalah entitas tunggal. Jika Anda memulai proyek baru, terlepas dari pengembangan lama, dan paket-paket akan diinstal menggunakan pip, maka Anda harus tetap menggunakan metode ini. Namun, terkadang kami mewarisi kode lama, yang juga perlu dipertahankan, setidaknya untuk sementara waktu, atau porting ke versi baru.
Mari kita beralih ke
Python 2.7 . Dengan versi ini sudah lebih menarik, Anda harus terlebih dahulu menambahkan __init__.py ke setiap direktori untuk membuat paket, jika tidak, penerjemah tidak akan mengenali paket dalam kumpulan file ini. Dan kemudian menulis deklarasi namespace eksplisit dalam file __init__ yang terkait dengan namespace1, jika tidak, hanya paket pertama yang akan diimpor.
from pkgutil import extend_path __path__ = extend_path(__path__, __name__)
Apa yang terjadi dengan ini? Ketika penerjemah mencapai impor pertama, sebuah paket dengan nama yang sama dicari di sys.path, itu di path1 / namespace1 dan penerjemah mengeksekusi path1 / namespace1 / __ init__.py. Pencarian lebih lanjut tidak dilakukan. Namun, fungsi extended_path sendiri melakukan pencarian di seluruh sys.path, menemukan semua paket dengan namespace1 dan nama internal dan menambahkannya ke variabel __path__ dari paket namespace1, yang digunakan untuk mencari paket anak di namespace ini.
Dalam panduan resmi, direkomendasikan bahwa inisialnya sama setiap kali namespace1 ditempatkan. Bahkan, mereka bisa kosong semua kecuali yang pertama, yang ditemukan selama pencarian di sys.path, di mana pkgutil.extend_path harus dipanggil, karena sisanya tidak dieksekusi. Namun, tentu saja, lebih baik panggilan itu benar-benar ada di setiap tim, agar tidak mengikat logika Anda "dalam kasus" dan tidak menebak tim mana yang pertama kali dieksekusi, karena urutan pencarian dapat berubah. Untuk alasan yang sama, Anda tidak boleh menempatkan file __init__ logika lain di area variabel.
Ini akan berfungsi di versi mendatang dan kode ini dapat digunakan untuk menulis
kode yang kompatibel , tetapi perlu diingat bahwa Anda harus mematuhi metode yang dipilih dalam setiap paket yang didistribusikan. Jika pada versi 3 Anda memasukkan in-box di beberapa paket dalam panggilan ke pkgutil.extend_path, dan meninggalkan beberapa tanpa in-box, ini tidak akan berfungsi.
Selain itu, opsi ini juga cocok untuk kasus ketika Anda berencana untuk menginstal menggunakan instalasi python setup.py.
Cara lain, yang sekarang dianggap agak ketinggalan zaman, tetapi masih bisa ditemukan banyak di mana:
Modul pkg_resources dilengkapi dengan paket setuptools. Di sini artinya sama dengan di pkgutil - perlu setiap file __init__ di setiap lokasi namespace1 berisi deklarasi namespace yang sama dan tidak ada kode lain. Pada saat yang sama, perlu mendaftarkan namespace namespace_packages = ['namespace1'] di setup.py. Deskripsi lebih rinci tentang pembuatan paket berada di luar cakupan artikel ini.
Selain itu, Anda sering dapat menemukan kode seperti itu
try: __import__('pkg_resources').declare_namespace(__name__) except: from pkgutil import extend_path __path__ = extend_path(__path__, __name__)
Di sini logikanya sederhana - jika setuptools tidak diinstal, maka kami menggunakan pkgutil, yang termasuk dalam pustaka standar.
Jika Anda mengkonfigurasi namespace dengan salah satu cara ini, Anda dapat memanggil yang lain dari satu modul. Misalnya, ubah namespace1 / package2 / module2
import namespace1.package1.module1 print(var1)
Dan kemudian kita akan melihat apa yang terjadi jika kita salah menamai paket baru serta yang sudah ada dan membungkusnya dengan namespace yang sama. Misalnya, akan ada dua paket di tempat yang berbeda dengan nama package1.
namespace1 package1 module1 package1 module2
Dalam hal ini, hanya yang pertama yang akan diimpor dan tidak akan ada akses ke module2. Paket tidak dapat digabungkan.
from namespace1.package1 import module1 from namespace1.package1 import module2
Ringkasan:- Untuk Python yang lebih tua dari 3,3 dan menginstal dengan pip, disarankan agar Anda menggunakan deklarasi namespace implisit.
- Dalam hal dukungan untuk versi 2 dan 3, serta instalasi dengan pemasangan pip dan python setup.py, opsi dengan pkgutil direkomendasikan.
- Opsi pkg_resources direkomendasikan jika Anda perlu mendukung paket yang lebih lama menggunakan metode ini, atau Anda perlu paket yang aman zip.
Sumber:
Contohnya dapat ditemukan di
sini .