Apakah __init__.py tidak diperlukan untuk paket dalam Python 3.3+


195

Saya menggunakan Python 3.5.1. Saya membaca dokumen dan bagian paket di sini: https://docs.python.org/3/tutorial/modules.html#packages

Sekarang, saya memiliki struktur berikut:

/home/wujek/Playground/a/b/module.py

module.py:

class Foo:
    def __init__(self):
        print('initializing Foo')

Sekarang, saat berada di /home/wujek/Playground:

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

Demikian pula, sekarang di rumah, superfolder dari Playground:

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

Sebenarnya, saya bisa melakukan segala macam hal:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

Mengapa ini bekerja? Saya __init__.pypikir perlu ada file (yang kosong akan bekerja) di keduanya adan buntuk module.pydapat diimpor ketika jalur Python menunjuk ke Playgroundfolder?

Ini tampaknya telah berubah dari Python 2.7:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

Dengan __init__.pykeduanya ~/Playground/adan ~/Playground/a/bitu berfungsi dengan baik.

Jawaban:


192

Python 3.3+ memiliki Paket Namespace Tersirat yang memungkinkannya untuk membuat paket tanpa __init__.pyfile.

Mengizinkan paket namespace implisit berarti bahwa persyaratan untuk menyediakan __init__.pyfile dapat dihapus sepenuhnya , dan terpengaruh ....

Cara lama dengan __init__.pyfile masih berfungsi seperti pada Python 2.


10
Saya akan membaca dokumen, tapi agak lama. Apakah mungkin untuk meringkas dengan cepat? Bisakah Anda memberi tahu saya: apakah masih mendukung init .py, atau sepenuhnya mengabaikannya? Jika memang mendukung mereka, apa perbedaan fungsi dan mengapa dualitas ini?
wujek

3
Jadi tutorial mungkin harus diperbarui. Apakah bug dokumentasi dibuka untuknya?
Michel Samia

4
Saya masih kesal karena ini menentang Zen Of Python baris 2: Explicit is better than implicit.....
JayRizzo

5
@JayRizzo But: "Meskipun kepraktisan mengalahkan kemurnian."
Mike Müller

19
@JayRizzo IMO bahkan lebih eksplisit. Kadang-kadang terjadi untuk melakukan hal-hal init __init__.py, kadang tidak. Dalam Python 3 ketika saya membutuhkan barang-barang ini saya membuat yang baru __init__.pydengan kode spesifik, kalau tidak saya tidak. Ini berguna untuk mengetahui, secara visual, paket mana yang memiliki init khusus. Alih-alih dalam python 2 saya selalu harus menempatkan __init__.py(sering kosong), membuat banyak dari mereka dan akhirnya lebih sulit untuk mengingat di mana Anda menempatkan kode init Anda. Ini juga harus sesuai "Harus ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukannya.".
Paolo

148

PENTING

@ Mike jawaban sudah benar tetapi juga tidak tepat. Memang benar bahwa Python 3.3+ mendukung Paket Namespace Implisit yang memungkinkannya untuk membuat paket tanpa__init__.py file.

Namun ini, HANYA berlaku untuk file KOSONG__init__.py . Jadi file KOSONG__init__.py tidak lagi diperlukan dan dapat dihilangkan. Jika Anda ingin menjalankan skrip inisialisasi tertentu ketika paket atau modul atau sub-paketnya diimpor, Anda masih memerlukan __init__.pyfile. Ini adalah jawaban Stack Overflow yang bagus untuk mengapa Anda ingin menggunakan __init__.pyfile untuk melakukan inisialisasi lebih lanjut jika Anda bertanya-tanya mengapa ini berguna.

Contoh Struktur Direktori:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

CONTOH

Contoh di bawah ini menunjukkan bagaimana skrip inisialisasi dijalankan ketika child_packageatau salah satu modulnya diimpor.

Contoh 1 :

from parent_package import child_package  # prints "from parent"

Contoh 2 :

from parent_package.child_package import child1  # prints "from parent"

2
Misalkan saya memiliki run_script.pydir yang sama parent_packagesehingga saya bisa mengimpor seperti from parent_package.child_package import child1tanpa __init__.py?
mrgloom

Apakah tujuannya agar Anda dapat menulis child_package.some_function bahkan jika some_function didefinisikan dalam childX.py? Dengan kata lain ia menghindari mengharuskan pengguna untuk mengetahui tentang berbagai file di child_package? ?
johnbakers

Ya, saya tidak mengerti mengapa Anda membuatnya child1.py, child2.pyalih-alih hanya menempatkan kode mereka ke dalam __init__.py secara langsung.
binki

Bukankah seharusnya pernyataan impor dalam bentuk __init__impor relatif from . import child1? Impor absolut memberi saya ModuleNotFoundError(dalam Python 3.6)
Halbeard

5
Dalam pengalaman saya, bahkan dengan python 3.3+, __init__.pykadang-kadang masih diperlukan yang kosong , seperti ketika Anda ingin merujuk subfolder sebagai sebuah paket. Misalnya, jika saya menjalankannya python -m test.footidak berfungsi sampai saya membuat kosong di __init__.pybawah folder tes. Dan saya berbicara tentang versi 3.6.6 di sini!
Prahlad Yeri

7

Jika Anda memiliki setup.pydalam proyek Anda dan Anda menggunakannya find_packages()di dalamnya, perlu memiliki __init__.pyfile di setiap direktori untuk paket yang akan ditemukan secara otomatis.

Paket hanya dikenali jika mereka menyertakan __init__.pyfile

UPD : Jika Anda ingin menggunakan paket namespace implisit tanpa __init__.pyAnda hanya perlu menggunakan find_namespace_packages()gantinya

Documents


2

Saya akan mengatakan bahwa seseorang harus menghilangkan __init__.pysatu - satunya jika seseorang ingin memiliki paket namespace implisit . Jika Anda tidak tahu apa artinya, Anda mungkin tidak menginginkannya dan oleh karena itu Anda harus terus menggunakan __init__.pybahkan dalam Python 3.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.