Bagaimana cara menulis file __init__.py paket yang baik / benar

188

Paket saya memiliki struktur berikut:

mobilescouter/
    __init__.py #1
    mapper/
        __init__.py  #2
        lxml/
            __init__.py #3
            vehiclemapper.py
            vehiclefeaturemapper.py
            vehiclefeaturesetmapper.py
        ...
        basemapper.py
   vehicle/
        __init__.py #4
        vehicle.py
        vehiclefeature.py
        vehiclefeaturemapper.py
   ...

Saya tidak yakin bagaimana __init__.pyfile harus ditulis dengan benar.
The __init__.py #1terlihat seperti:

__all__ = ['mapper', 'vehicle']
import mapper
import vehicle

Tetapi bagaimana seharusnya misalnya __init__.py #2terlihat seperti? Punya saya:

__all__ = ['basemapper', 'lxml']
from basemaper import *
import lxml

Kapan sebaiknya __all__digunakan?

Marten Bauer
sumber
3
Ketahuilah bahwa menggunakan impor * dalam kode umumnya merupakan praktik yang sangat buruk dan harus dihindari jika mungkin. Ada beberapa kasus penggunaan yang baik untuk ini, tetapi mereka benar-benar langka.
Mayou36
PSA: jika Anda tertarik mempelajari cara menulis paket namespace yang bagus (jenis baru dari paket), lihat paket contoh ini: github.com/pypa/sample-namespace-packages
Kyle

Jawaban:

146

__all__sangat baik - ini membantu memandu pernyataan impor tanpa secara otomatis mengimpor modul http://docs.python.org/tutorial/modules.html#importing-from-a-package

menggunakan __all__dan import *berlebihan, hanya __all__diperlukan

Saya pikir salah satu alasan paling kuat untuk digunakan import *dalam __init__.pymengimpor paket adalah untuk dapat membuat ulang skrip yang telah berkembang menjadi banyak skrip tanpa merusak aplikasi yang ada. Tetapi jika Anda merancang paket dari awal. Saya pikir yang terbaik adalah membiarkan __init__.pyfile kosong.

sebagai contoh:

foo.py - contains classes related to foo such as fooFactory, tallFoo, shortFoo

lalu aplikasi tumbuh dan sekarang menjadi seluruh folder

foo/
    __init__.py
    foofactories.py
    tallFoos.py
    shortfoos.py
    mediumfoos.py
    santaslittlehelperfoo.py
    superawsomefoo.py
    anotherfoo.py

maka skrip init dapat mengatakan

__all__ = ['foofactories', 'tallFoos', 'shortfoos', 'medumfoos',
           'santaslittlehelperfoo', 'superawsomefoo', 'anotherfoo']
# deprecated to keep older scripts who import this from breaking
from foo.foofactories import fooFactory
from foo.tallfoos import tallFoo
from foo.shortfoos import shortFoo

sehingga skrip yang ditulis untuk melakukan hal berikut tidak rusak selama perubahan:

from foo import fooFactory, tallFoo, shortFoo
Fire Crow
sumber
3
Saya sangat bingung tentang ' semua ' dan impor baris demi baris. Teladan Anda sangat mencerahkan.
Junchen
2
Saya bingung dengan " __all__dan import *redundan", __all__digunakan oleh konsumen modul, dan from foo import *digunakan oleh modul itu sendiri untuk menggunakan yang lain ....
Nick T
using __all__ and import * is redundant, only __all__ is needed Bagaimana itu berlebihan? Mereka melakukan hal yang berbeda.
endolith
113

__init__.pyFile saya sendiri kosong lebih sering daripada tidak. Secara khusus, saya tidak pernah memiliki from blah import *sebagai bagian dari __init__.py- jika "mengimpor paket" berarti mendapatkan semua jenis kelas, fungsi dll yang didefinisikan langsung sebagai bagian dari paket, maka saya akan secara leksikal menyalin konten blah.pyke dalam paket __init__.pysebagai gantinya dan menghapus blah.py( perbanyakan file sumber tidak ada gunanya di sini).

Jika Anda bersikeras mendukung import *idiom (eek), kemudian menggunakan __all__(dengan sangat kecil daftar nama yang dapat Anda bawa sendiri) dapat membantu untuk pengendalian kerusakan. Secara umum, ruang nama dan impor eksplisit adalah hal yang baik , dan saya sangat menyarankan untuk mempertimbangkan kembali setiap pendekatan berdasarkan secara sistematis melewati salah satu atau kedua konsep! -)

Alex Martelli
sumber
9
Secara pribadi, saya lebih suka memisahkan barang-barang, lalu mengimpor *. Alasannya adalah bahwa, meskipun ada lipatan dan semacamnya, saya masih benci menelusuri file yang berisi terlalu banyak kelas, meskipun terkait.
Stefano Borini
5
@stefano berpikir tentang kerangka besar. jika menggunakan import *Anda harus tanpa syarat menerima semua kerangka kerja dalam semua itu, bahkan fitur yang Anda tidak akan pernah gunakan. menjaga __init__.pykosong memberi Anda lebih banyak peluang daripada hanya semantik semua atau tidak sama sekali. pikirkan tentang bengkok.
mg.
jika tetap kosong, bahkan setelah mengimpor mobilescouter, orang masih tidak dapat menggunakan mobilescouter.mapper atau mobilescouter.vehicle atau mobilescouter.apapun. bukankah impor mobilescouter.A, mobilescouter.B ..... terlalu bertele-tele?
sunqiang
6
@ Sunqiang ini pribadi tapi saya rasa tidak. from mobilescouter import A, Bhanya sebaris kode dan Anda tidak memiliki proyek dengan 666 kelas dan setiap orang dengan file sendiri, kan? jika Anda memiliki dua atau lebih import *kode Anda mengisi ruang nama dengan potensi sampah dan dengan cepat Anda akan lupa dari mana Aasalnya. Dan jika paket atas melakukan hal yang sama? Anda mengambil semua sub-paket dan sub-paket. seperti kata zen dari python, eksplisit lebih baik daripada implisit.
mg.
1
@ mg, jika ada baris "import A, B" di init .py file, maka saya bisa memanggil A (atau B) dengan sintaks: mobilescouter.A; jika kita menggunakan "dari impor mobilescouter A, B", maka itu hanya A. sesuatu. kadang hanya baris ini, saya tidak ingat A adalah sub pacakge dari mobilescouter, dan saya pikir ini berkontribusi pada polusi namespace (meskipun jauh lebih baik daripada "" dari impor mobilescouter * ". Saya masih lebih suka" import pkgname "beri pengguna . antarmuka publik seragam sehingga init py melakukan hal-hal impor sub_pkgname.
sunqiang
1

Anda __init__.pyharus memiliki docstring .

Meskipun semua fungsi diimplementasikan dalam modul dan subpackages, paket dokumentasi Anda adalah tempat untuk mendokumentasikan tempat untuk memulai. Sebagai contoh, pertimbangkan paket pythonemail . Dokumentasi paket adalah pengantar yang menjelaskan tujuan, latar belakang, dan bagaimana berbagai komponen dalam paket bekerja bersama. Jika Anda secara otomatis membuat dokumentasi dari dokumen menggunakan sphinx atau paket lain, paket dokumentasi tersebut adalah tempat yang tepat untuk menggambarkan pengantar tersebut.

Untuk konten lain, lihat jawaban yang sangat bagus dari firecrow dan Alex Martelli .

gerrit
sumber
Apakah yang sebenarnya __init__.pyuntuk emailpaket mengikuti panduan ini? Saya melihat satu baris docstring yang tidak banyak menjelaskan "bagaimana berbagai komponen dalam paket bekerja bersama".
Gertlex
@Gertlex Mungkin hanya di dokumentasi web.
gerrit