Jawaban:
Ini adalah daftar objek publik dari modul itu, sebagaimana ditafsirkan oleh import *
. Itu menimpa default menyembunyikan segala sesuatu yang dimulai dengan garis bawah.
import *
(seperti misalnya tk
). Petunjuk yang bagus jika hal ini terjadi adalah keberadaan __all__
atau nama yang dimulai dengan garis bawah pada kode modul.
tk
dirilis hari ini (atau pada 2012, bahkan), praktik yang disarankan adalah menggunakan from tk import *
. Saya pikir praktik ini diterima karena inersia, bukan desain yang disengaja.
Tertaut ke, tetapi tidak secara eksplisit disebutkan di sini, adalah persis kapan __all__
digunakan. Ini adalah daftar string yang mendefinisikan simbol apa dalam modul yang akan diekspor saat from <module> import *
digunakan pada modul.
Misalnya, kode berikut foo.py
secara eksplisit mengekspor simbol bar
dan baz
:
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'
Simbol-simbol ini kemudian dapat diimpor seperti:
from foo import *
print(bar)
print(baz)
# The following will trigger an exception, as "waz" is not exported by the module
print(waz)
Jika di __all__
atas dikomentari, kode ini kemudian akan dieksekusi sampai selesai, karena perilaku default import *
adalah mengimpor semua simbol yang tidak dimulai dengan garis bawah, dari namespace yang diberikan.
Referensi: https://docs.python.org/tutorial/modules.html#importing-from-a-package
CATATAN: hanya __all__
mempengaruhi from <module> import *
perilaku. Anggota yang tidak disebutkan dalam __all__
masih dapat diakses dari luar modul dan dapat diimpor dengan from <module> import <member>
.
print(baz())
?
print(baz)
mencetak sesuatu seperti cetakan <function baz at 0x7f32bc363c10>
sementaraprint(baz())
baz
Jelaskan __all__ dengan Python?
Saya terus melihat
__all__
set variabel dalam__init__.py
file yang berbeda .Apa fungsinya?
__all__
harus dilakukanIni mendeklarasikan nama "publik" semantik dari sebuah modul. Jika ada nama di __all__
, pengguna diharapkan untuk menggunakannya, dan mereka dapat memiliki harapan bahwa itu tidak akan berubah.
Itu juga akan memiliki dampak terprogram:
import *
__all__
dalam sebuah modul, misalnya module.py
:
__all__ = ['foo', 'Bar']
berarti bahwa ketika Anda import *
dari modul, hanya nama-nama dalam __all__
yang diimpor:
from module import * # imports foo and Bar
Alat dokumentasi dan pelengkapan otomatis kode dapat (pada kenyataannya, harus) juga memeriksa __all__
untuk menentukan nama yang akan ditampilkan sebagai tersedia dari modul.
__init__.py
membuat direktori paket PythonDari dokumen :
The
__init__.py
file yang diperlukan untuk membuat Python memperlakukan direktori sebagai mengandung paket; ini dilakukan untuk mencegah direktori dengan nama umum, seperti string, dari menyembunyikan modul valid yang terjadi kemudian pada jalur pencarian modul.Dalam kasus yang paling sederhana,
__init__.py
bisa berupa file kosong, tetapi juga dapat mengeksekusi kode inisialisasi untuk paket atau mengatur__all__
variabel.
Jadi __init__.py
dapat mendeklarasikan __all__
untuk paket .
Paket biasanya terdiri dari modul yang dapat mengimpor satu sama lain, tetapi yang harus diikat bersama dengan __init__.py
file. File itu yang membuat direktori paket Python yang sebenarnya. Misalnya, Anda memiliki file berikut dalam satu paket:
package
├── __init__.py
├── module_1.py
└── module_2.py
Mari kita buat file-file ini dengan Python sehingga Anda dapat mengikuti - Anda dapat menempelkan yang berikut ke dalam shell Python 3:
from pathlib import Path
package = Path('package')
package.mkdir()
(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")
package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")
package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")
Dan sekarang Anda telah menyajikan api lengkap yang dapat digunakan orang lain saat mereka mengimpor paket Anda, seperti:
import package
package.foo()
package.Bar()
Dan paket tidak akan memiliki semua detail implementasi lain yang Anda gunakan saat membuat modul Anda mengacaukan package
namespace.
__all__
di __init__.py
Setelah lebih banyak pekerjaan, mungkin Anda telah memutuskan bahwa modul terlalu besar (seperti ribuan baris?) Dan perlu dipisah. Jadi, Anda melakukan hal berikut:
package
├── __init__.py
├── module_1
│ ├── foo_implementation.py
│ └── __init__.py
└── module_2
├── Bar_implementation.py
└── __init__.py
Pertama-tama buat direktori subpackage dengan nama yang sama dengan modul:
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
Pindahkan implementasinya:
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
buat __init__.py
s untuk sub paket yang menyatakan __all__
untuk masing-masing:
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
Dan sekarang Anda masih memiliki api yang disediakan di tingkat paket:
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
Dan Anda dapat dengan mudah menambahkan hal-hal ke API Anda yang dapat Anda kelola di tingkat sub-paket bukan tingkat modul sub-paket. Jika Anda ingin menambahkan nama baru ke API, Anda cukup memperbarui __init__.py
, misalnya di module_2:
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
Dan jika Anda belum siap untuk mempublikasikan Baz
di API tingkat atas, di level teratas __init__.py
Anda, Anda dapat memiliki:
from .module_1 import * # also constrained by __all__'s
from .module_2 import * # in the __init__.py's
__all__ = ['foo', 'Bar'] # further constraining the names advertised
dan jika pengguna Anda mengetahui ketersediaan Baz
, mereka dapat menggunakannya:
import package
package.Baz()
tetapi jika mereka tidak mengetahuinya, alat lain (seperti pydoc ) tidak akan memberi tahu mereka.
Anda nanti dapat mengubahnya saat Baz
siap untuk prime time:
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
_
versus __all__
:Secara default, Python akan mengekspor semua nama yang tidak dimulai dengan _
. Anda tentu bisa mengandalkan mekanisme ini. Beberapa paket di pustaka standar Python, pada kenyataannya, memang mengandalkan ini, tetapi untuk melakukannya, mereka alias impor mereka, misalnya, di ctypes/__init__.py
:
import os as _os, sys as _sys
Menggunakan _
konvensi dapat menjadi lebih elegan karena menghilangkan redundansi penamaan nama lagi. Tetapi itu menambah redundansi untuk impor (jika Anda memiliki banyak impor) dan mudah untuk melupakan hal ini secara konsisten - dan hal terakhir yang Anda inginkan adalah harus tanpa batas mendukung sesuatu yang Anda maksudkan hanya menjadi detail implementasi, hanya saja karena Anda lupa untuk awalan _
ketika memberi nama fungsi.
Saya pribadi menulis __all__
awal dalam siklus hidup pengembangan saya untuk modul sehingga orang lain yang mungkin menggunakan kode saya tahu apa yang harus mereka gunakan dan tidak gunakan.
Sebagian besar paket di perpustakaan standar juga digunakan __all__
.
__all__
masuk akalMasuk akal untuk tetap berpegang pada _
konvensi awalan sebagai pengganti __all__
ketika:
export
dekoratorKelemahan dari penggunaan __all__
adalah bahwa Anda harus menulis nama fungsi dan kelas yang diekspor dua kali - dan informasi disimpan terpisah dari definisi. Kita bisa menggunakan dekorator untuk menyelesaikan masalah ini.
Saya mendapat ide untuk dekorator ekspor dari pembicaraan David Beazley tentang pengemasan. Implementasi ini tampaknya bekerja dengan baik di importir tradisional CPython. Jika Anda memiliki kait atau sistem impor khusus, saya tidak menjaminnya, tetapi jika Anda mengadopsinya, itu cukup sepele untuk mundur - Anda hanya perlu menambahkan nama secara manual ke dalam__all__
Jadi di, misalnya, perpustakaan utilitas, Anda akan mendefinisikan dekorator:
import sys
def export(fn):
mod = sys.modules[fn.__module__]
if hasattr(mod, '__all__'):
mod.__all__.append(fn.__name__)
else:
mod.__all__ = [fn.__name__]
return fn
dan kemudian, di mana Anda akan mendefinisikan __all__
, Anda melakukan ini:
$ cat > main.py
from lib import export
__all__ = [] # optional - we create a list if __all__ is not there.
@export
def foo(): pass
@export
def bar():
'bar'
def main():
print('main')
if __name__ == '__main__':
main()
Dan ini berfungsi baik apakah dijalankan sebagai utama atau diimpor oleh fungsi lain.
$ cat > run.py
import main
main.main()
$ python run.py
main
Dan penyediaan API dengan import *
akan bekerja juga:
$ cat > run.py
from main import *
foo()
bar()
main() # expected to error here, not exported
$ python run.py
Traceback (most recent call last):
File "run.py", line 4, in <module>
main() # expected to error here, not exported
NameError: name 'main' is not defined
@export
dekorator.
__init__.py
dan penggunaan__all__
__all__
itu benar.
__all__
juga - tapi kemudian saya akan mengatakan Anda memiliki API tidak stabil ... Ini akan menjadi sesuatu untuk memiliki beberapa tes penerimaan yang komprehensif.
module_1
dan module_2
; apakah boleh memasukkan eksplisit del module_1
dalam __init__.py
? Apakah saya salah menganggap ini berharga?
Saya hanya menambahkan ini tepatnya:
Semua jawaban lain merujuk pada modul . Pertanyaan asli secara eksplisit disebutkan __all__
dalam __init__.py
file, jadi ini tentang paket python .
Umumnya, __all__
hanya berlaku ketika from xxx import *
varian import
pernyataan digunakan. Ini berlaku untuk paket dan juga untuk modul.
Perilaku untuk modul dijelaskan dalam jawaban lain. Perilaku yang tepat untuk paket dijelaskan di sini secara rinci.
Singkatnya, __all__
pada tingkat paket melakukan hal yang kira-kira sama dengan untuk modul, kecuali itu berkaitan dengan modul dalam paket (berbeda dengan menentukan nama-nama dalam modul ). Jadi __all__
tentukan semua modul yang akan dimuat dan diimpor ke namespace saat ini saat kami gunakan from package import *
.
Perbedaan besar adalah, bahwa ketika Anda menghilangkan deklarasi __all__
dalam sebuah paket __init__.py
, pernyataan from package import *
itu tidak akan mengimpor apa pun (dengan pengecualian yang dijelaskan dalam dokumentasi, lihat tautan di atas).
Di sisi lain, jika Anda menghilangkan __all__
dalam sebuah modul, "impor berbintang" akan mengimpor semua nama (tidak dimulai dengan garis bawah) yang ditentukan dalam modul.
from package import *
masih akan mengimpor semua yang didefinisikan __init__.py
, bahkan jika tidak ada all
. Perbedaan penting adalah bahwa tanpa __all__
itu tidak akan secara otomatis mengimpor modul yang ditentukan dalam direktori paket.
Itu juga mengubah apa yang akan ditampilkan pydoc:
module1.py
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc module1
Bantuan pada module module1: NAMA modul 1 MENGAJUKAN module1.py DATA a = 'A' b = 'B' c = 'C'
$ pydoc module2
Bantuan pada module module2: NAMA module2 MENGAJUKAN module2.py DATA __all__ = ['a', 'b'] a = 'A' b = 'B'
Saya menyatakan __all__
dalam semua modul saya, serta menggarisbawahi detail internal, ini sangat membantu ketika menggunakan hal-hal yang belum pernah Anda gunakan sebelumnya dalam sesi penerjemah langsung.
__all__
menyesuaikan *
difrom <module> import *
__all__
menyesuaikan *
difrom <package> import *
Sebuah modul adalah .py
file yang dimaksudkan untuk diimpor.
Sebuah paket adalah direktori dengan __init__.py
file yang. Paket biasanya berisi modul.
""" cheese.py - an example module """
__all__ = ['swiss', 'cheddar']
swiss = 4.99
cheddar = 3.99
gouda = 10.99
__all__
memungkinkan manusia mengetahui fitur "publik" dari sebuah modul . [ @AaronHall ] Juga, pydoc mengenali mereka. [ @Longpoke ]
Lihat bagaimana swiss
dan cheddar
dibawa ke ruang nama lokal, tetapi tidak gouda
:
>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined
Tanpa __all__
, simbol apa pun (yang tidak dimulai dengan garis bawah) akan tersedia.
*
tidak terpengaruh oleh__all__
>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)
>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)
>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)
Dalam __init__.py
file paket __all__
adalah daftar string dengan nama-nama modul publik atau objek lainnya. Fitur-fitur tersebut tersedia untuk impor wildcard. Seperti halnya modul, __all__
sesuaikan *
kapan wildcard mengimpor dari paket. [ @MartinStettner ]
Berikut ini kutipan dari Konektor Python MySQL __init__.py
:
__all__ = [
'MySQLConnection', 'Connect', 'custom_error_exception',
# Some useful constants
'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
'HAVE_CEXT',
# Error handling
'Error', 'Warning',
...etc...
]
Kasing standar, tanda bintang tanpa __all__
paket , rumit, karena perilaku yang jelas akan mahal: menggunakan sistem file untuk mencari semua modul dalam paket. Sebaliknya, dalam membaca dokumen saya, hanya objek yang didefinisikan __init__.py
diimpor:
Jika
__all__
tidak didefinisikan, pernyataanfrom sound.effects import *
itu tidak mengimpor semua submodul dari paketsound.effects
ke namespace saat ini; hanya memastikan bahwa paketsound.effects
telah diimpor (mungkin menjalankan kode inisialisasi apa pun__init__.py
) dan kemudian mengimpor nama apa pun yang didefinisikan dalam paket. Ini termasuk nama apa pun yang didefinisikan (dan submodul yang dimuat secara eksplisit) oleh__init__.py
. Ini juga termasuk semua submodul dari paket yang secara eksplisit dimuat oleh pernyataan impor sebelumnya.
Impor wildcard ... harus dihindari karena mereka [membingungkan] pembaca dan banyak alat otomatis.
[ PEP 8 , @ToolmakerSteve]
from <package> import *
tanpa __all__
di __init__.py
yang tidak mengimpor modul .
__init__.py
modul . Tapi saya tidak yakin itu akurat, atau khususnya jika objek garis bawah-awalan dikecualikan. Juga, saya lebih jelas memisahkan bagian tentang MODUL dan PAKET. Pikiran Anda?
Dari Wiki Referensi Python (An Tidak Resmi) :
Nama publik yang ditentukan oleh modul ditentukan dengan memeriksa namespace modul untuk variabel bernama
__all__
; jika didefinisikan, harus berupa urutan string yang merupakan nama yang didefinisikan atau diimpor oleh modul itu. Semua nama yang diberikan__all__
dianggap publik dan harus ada. Jika__all__
tidak didefinisikan, himpunan nama publik mencakup semua nama yang ditemukan di namespace modul yang tidak dimulai dengan karakter garis bawah ("_").__all__
harus mengandung seluruh API publik. Hal ini dimaksudkan untuk menghindari ekspor barang yang bukan bagian dari API (seperti modul perpustakaan yang diimpor dan digunakan dalam modul).
__all__
digunakan untuk mendokumentasikan API publik dari modul Python. Meskipun bersifat opsional, __all__
harus digunakan.
Berikut adalah kutipan yang relevan dari referensi bahasa Python :
Nama publik yang ditentukan oleh modul ditentukan dengan memeriksa namespace modul untuk variabel bernama
__all__
; jika didefinisikan, harus berupa urutan string yang merupakan nama yang didefinisikan atau diimpor oleh modul itu. Semua nama yang diberikan__all__
dianggap publik dan harus ada. Jika__all__
tidak didefinisikan, himpunan nama publik mencakup semua nama yang ditemukan di namespace modul yang tidak dimulai dengan karakter garis bawah ('_').__all__
harus mengandung seluruh API publik. Hal ini dimaksudkan untuk menghindari ekspor barang yang bukan bagian dari API (seperti modul perpustakaan yang diimpor dan digunakan dalam modul).
PEP 8 menggunakan kata-kata yang serupa, meskipun juga menjelaskan bahwa nama yang diimpor bukan bagian dari API publik ketika __all__
tidak ada:
Untuk mendukung introspeksi dengan lebih baik, modul harus secara eksplisit mendeklarasikan nama-nama di API publik mereka menggunakan
__all__
atribut. Pengaturan__all__
ke daftar kosong menunjukkan bahwa modul tidak memiliki API publik.[...]
Nama yang diimpor harus selalu dianggap sebagai detail implementasi. Modul-modul lain tidak boleh mengandalkan akses tidak langsung ke nama-nama yang diimpor tersebut kecuali mereka merupakan bagian yang terdokumentasi secara eksplisit dari API modul yang mengandung, seperti
os.path
atau__init__
modul paket yang memperlihatkan fungsionalitas dari submodul.
Selanjutnya, seperti yang ditunjukkan dalam jawaban lain, __all__
digunakan untuk mengaktifkan wildcard mengimpor untuk paket :
Pernyataan impor menggunakan konvensi berikut: jika
__init__.py
kode paket mendefinisikan daftar bernama__all__
, itu diambil menjadi daftar nama modul yang harus diimpor ketikafrom package import *
ditemui.
__all__
memengaruhi from <module> import *
pernyataan.
Pertimbangkan contoh ini:
foo
├── bar.py
└── __init__.py
Dalam foo/__init__.py
:
(Tersirat) Jika kami tidak mendefinisikan __all__
, maka from foo import *
hanya akan mengimpor nama yang didefinisikan dalam foo/__init__.py
.
(Eksplisit) Jika kita mendefinisikan __all__ = []
, maka tidak from foo import *
akan mengimpor apa pun.
(Eksplisit) Jika kita mendefinisikan __all__ = [ <name1>, ... ]
, maka from foo import *
hanya akan mengimpor nama-nama itu.
Perhatikan bahwa dalam kasus tersirat, python tidak akan mengimpor nama yang dimulai dengan _
. Namun, Anda dapat memaksa mengimpor nama tersebut menggunakan __all__
.
Anda dapat melihat dokumen Python di sini .
__all__
mempengaruhi cara from foo import *
kerjanya.
Kode yang ada di dalam tubuh modul (tetapi tidak di tubuh fungsi atau kelas) dapat menggunakan tanda bintang ( *
) dalam from
pernyataan:
from foo import *
The *
permintaan bahwa semua atribut modul foo
(kecuali yang awal dengan garis bawah) terikat sebagai variabel global dalam modul mengimpor. Ketika foo
memiliki atribut __all__
, nilai atribut adalah daftar nama-nama yang terikat oleh jenis from
pernyataan ini.
Jika foo
sebuah paket dan __init__.py
mendefinisikan daftar bernama __all__
, itu diambil menjadi daftar nama submodule yang harus diimpor ketika from foo import *
ditemui. Jika __all__
tidak didefinisikan, pernyataan from foo import *
mengimpor nama apa pun yang didefinisikan dalam paket. Ini termasuk nama apa pun yang didefinisikan (dan submodul yang dimuat secara eksplisit) oleh __init__.py
.
Catatan yang __all__
tidak harus menjadi daftar. Sesuai dokumentasi pada import
pernyataan , jika ditentukan, __all__
harus berupa urutan string yang merupakan nama yang didefinisikan atau diimpor oleh modul. Jadi, Anda sebaiknya menggunakan tuple untuk menghemat beberapa siklus memori dan CPU. Hanya saja, jangan lupa koma jika modul mendefinisikan satu nama publik:
__all__ = ('some_name',)
Lihat juga Mengapa “impor *” buruk?
Ini didefinisikan dalam PEP8 di sini :
Nama Variabel Global
(Mari kita berharap bahwa variabel-variabel ini dimaksudkan untuk digunakan di dalam satu modul saja.) Konvensi hampir sama dengan yang untuk fungsi.
Modul yang dirancang untuk digunakan melalui
from M import *
harus menggunakan__all__
mekanisme untuk mencegah ekspor global, atau menggunakan konvensi yang lebih lama untuk mengawali globalisasi tersebut dengan garis bawah (yang mungkin ingin Anda lakukan untuk menunjukkan bahwa global ini adalah "modul non-publik").
PEP8 menyediakan konvensi pengkodean untuk kode Python yang terdiri dari pustaka standar dalam distribusi Python utama. Semakin banyak Anda mengikuti ini, semakin dekat Anda dengan maksud aslinya.
__all__
jika__all__
ada, tidak sepenuhnya tersembunyi; mereka dapat dilihat dan diakses dengan normal jika Anda tahu namanya. Hanya dalam kasus "impor *", yang tidak dianjurkan, perbedaannya memiliki bobot.