Setelah menggunakan paket datar, saya tidak mengharapkan masalah yang saya temui dengan paket bersarang. Disini adalah…
Tata letak direktori
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Isi init .py
Keduanya package/__init__.py
dan package/subpackage/__init__.py
kosong.
Isi dari module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
Isi dari test.py
(3 versi)
Versi 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK
Itu cara yang buruk dan tidak aman untuk mengimpor barang (impor semua dalam jumlah besar), tetapi berhasil.
Versi 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Cara yang lebih aman untuk mengimpor, item demi item, tetapi gagal, Python tidak menginginkan ini: gagal dengan pesan: "No module bernama module". Namun…
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
… Berkata <module 'package.subpackage.module' from '...'>
. Jadi itu modul, tapi itu bukan modul / -P 8-O ... uh
Versi 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Yang ini berhasil. Jadi Anda terpaksa menggunakan awalan yang berlebihan sepanjang waktu atau menggunakan cara yang tidak aman seperti pada versi # 1 dan tidak diizinkan oleh Python untuk menggunakan cara praktis yang aman? Cara yang lebih baik, mana yang aman dan menghindari awalan panjang yang tidak perlu adalah satu-satunya yang ditolak Python? Apakah ini karena cinta import *
atau karena menyukai prefiks yang terlalu panjang (yang tidak membantu untuk menegakkan praktik ini)?
Maaf untuk kata-kata sulitnya, tapi itu dua hari saya mencoba untuk mengatasi perilaku bodoh ini. Kecuali jika saya benar-benar salah, ini akan membuat saya merasa ada sesuatu yang benar-benar rusak dalam model paket dan sub-paket Python.
Catatan
- Saya tidak ingin mengandalkan
sys.path
, untuk menghindari efek samping global, atau*.pth
file, yang hanya merupakan cara lain untuk bermainsys.path
dengan efek global yang sama. Agar solusinya bersih, harus lokal saja. Entah Python dapat menangani sub-paket, baik itu tidak, tetapi tidak perlu bermain dengan konfigurasi global untuk dapat menangani barang-barang lokal. - Saya juga mencoba menggunakan impor
package/subpackage/__init__.py
, tetapi tidak menyelesaikan apa-apa, melakukan hal yang sama, dan komplainsubpackage
bukan modul yang dikenal, sementaraprint subpackage
mengatakan ini adalah modul (perilaku aneh, sekali lagi).
Mungkin saya sepenuhnya salah tangguh (opsi yang saya lebih suka), tetapi ini membuat saya merasa sangat kecewa dengan Python.
Adakah cara lain yang diketahui selain dari ketiganya yang saya coba? Sesuatu yang tidak saya ketahui?
(mendesah)
-----% <----- edit ----->% -----
Kesimpulan sejauh ini (setelah komentar orang)
Tidak ada sub-paket nyata dalam Python, karena semua referensi paket hanya masuk ke kamus global, yang berarti tidak ada kamus lokal, yang berarti tidak ada cara untuk mengelola referensi paket lokal.
Anda harus menggunakan prefiks penuh atau prefiks pendek atau alias. Seperti dalam:
Versi awalan lengkap
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Versi awalan pendek (tapi awalan berulang)
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place
Atau, variasi di atas.
from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context
Versi terfaktor
Jika Anda tidak keberatan mengimpor beberapa entitas sekaligus dalam satu batch, Anda dapat:
from package.subpackage.module import attribute1, attribute2
# and etc.
Tidak dalam rasa favorit pertama saya (saya lebih suka memiliki satu pernyataan impor per entitas yang diimpor), tetapi mungkin yang saya sukai secara pribadi.
Pembaruan (2012-09-14):
Akhirnya tampaknya OK dalam praktiknya, kecuali dengan komentar tentang tata letak. Alih-alih di atas, saya menggunakan:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.
__all__
variabel yang berisi daftar nama yang harus diekspor saat diimpor. edit: Oke, membaca jawaban BrenBarn saya mengerti apa yang Anda maksud.Jawaban:
Anda tampaknya salah paham tentang cara
import
menelusuri modul. Saat Anda menggunakan pernyataan import, ia selalu mencari jalur modul aktual (dan / atausys.modules
); itu tidak menggunakan objek modul di namespace lokal yang ada karena impor sebelumnya. Saat kamu melakukan:import package.subpackage.module from package.subpackage import module from module import attribute1
Baris kedua mencari paket yang dipanggil
package.subpackage
dan mengimpormodule
dari paket itu. Baris ini tidak berpengaruh pada baris ketiga. Baris ketiga hanya mencari modul yang dipanggilmodule
dan tidak menemukannya. Itu tidak "menggunakan kembali" objek yang disebutmodule
yang Anda dapatkan dari baris di atas.Dengan kata lain
from someModule import ...
tidak berarti "dari modul bernama someModule yang saya impor sebelumnya ..." itu berarti "dari modul bernama someModule yang Anda temukan di sys.path ...". Tidak ada cara untuk "secara bertahap" membangun jalur modul dengan mengimpor paket yang mengarah ke sana. Anda selalu harus merujuk ke seluruh nama modul saat mengimpor.Tidak jelas apa yang ingin Anda capai. Jika Anda hanya ingin mengimpor atribut objek1 tertentu, lakukan
from package.subpackage.module import attribute1
dan selesaikan saja. Anda tidak perlu khawatir tentang lamapackage.subpackage.module
setelah Anda mengimpor nama yang Anda inginkan darinya.Jika Anda tidak ingin memiliki akses ke modul untuk mengakses nama lain nanti, maka Anda dapat melakukan
from package.subpackage import module
dan, karena Anda telah melihat Anda kemudian dapat melakukanmodule.attribute1
dan sebagainya sebanyak yang Anda suka.Jika Anda menginginkan keduanya --- yaitu, jika Anda ingin
attribute1
dapat diakses secara langsung dan inginmodule
dapat diakses, cukup lakukan kedua hal di atas:from package.subpackage import module from package.subpackage.module import attribute1 attribute1 # works module.someOtherAttribute # also works
Jika Anda tidak suka mengetik
package.subpackage
dua kali, Anda dapat membuat referensi lokal ke atribut1 secara manual:from package.subpackage import module attribute1 = module.attribute1 attribute1 # works module.someOtherAttribute #also works
sumber
module.attribute1
adalah sesuatu yang saya pikirkan, tapi saya pikir akan ada cara untuk menghindari perlunya prefiks di mana-mana. Jadi saya harus menggunakan awalan di mana-mana, atau membuat alias lokal, mengulangi nama tersebut. Bukan gaya yang saya harapkan, tetapi jika tidak ada cara (lagipula, saya sudah terbiasa dengan Ada, yang membutuhkan sesuatu yang mirip dengan deklarasi penggantian nama).Alasan # 2 gagal adalah karena
sys.modules['module']
tidak ada (rutin impor memiliki cakupannya sendiri, dan tidak dapat melihatmodule
nama lokal), dan tidak adamodule
modul atau paket di disk. Perhatikan bahwa Anda dapat memisahkan beberapa nama yang diimpor dengan koma.from package.subpackage.module import attribute1, attribute2, attribute3
Juga:
from package.subpackage import module print module.attribute1
sumber
sys.modules['name']
yang saya tidak tahu sampai sekarang, membuat saya berpikir itulah yang saya takuti (dan BrenBarn menegaskan): tidak ada yang seperti sub-paket nyata dalam Python.sys.modules
, seperti yang disarankan namanya, bersifat global, dan jika semua referensi ke modul mengandalkan ini, maka tidak ada yang seperti referensi lokal ke modul (mungkin datang dengan Python 3.x?).import
di # 2 menghasilkan referensi lokal untukpackage.subpackage.module
terikatmodule
.Jika semua yang Anda coba lakukan adalah mendapatkan atribut1 di namespace global Anda, versi 3 tampaknya baik-baik saja. Mengapa prefiks itu berlebihan?
Di versi 2, bukan
from module import attribute1
Anda dapat melakukan
sumber
attribute1 = module.attribute1
hanya mengulang nama tanpa nilai tambah. Saya tahu ini berhasil, tetapi saya tidak suka gaya ini (yang tidak berarti saya tidak suka balasan Anda).