Yanıtlar:
Eskiden bir paketin gerekli bir parçasıydı ( eski, 3.3'ten önceki "normal paket" , daha yeni 3.3+ "ad alanı paketi" değil ).
Python iki tür paket tanımlar, normal paketler ve ad alanı paketleri. Normal paketler, Python 3.2 ve önceki sürümlerde var oldukları için geleneksel paketlerdir. Normal bir paket genellikle
__init__.py
dosya içeren bir dizin olarak uygulanır . Normal bir paket içe aktarıldığında, bu__init__.py
dosya dolaylı olarak yürütülür ve tanımladığı nesneler paketin ad alanındaki adlara bağlanır.__init__.py
Dosya başka modül içerebilir aynı Python kodunu içerebilir ve içe aktarıldığında Python modülüne bazı ek özellikler eklemek olacaktır.
Ancak sadece bağlantıyı tıklayın, bir örnek, daha fazla bilgi ve ad alanı paketlerinin açıklaması, olmayan paketler türünü içerir __init__.py
.
sys.path.insert(0, '/path/to/datetime')
bu yolu yeni yaptığınız dizine giden yolla değiştirin. Şimdi böyle bir şey deneyin from datetime import datetime;datetime.now()
. Bir AttributeError almalısınız (çünkü boş dosyanızı şimdi içe aktarıyor). Bu adımları boş init dosyası oluşturmadan tekrarlayacak olsaydınız bu olmazdı. Önlemek istediği bu.
from datetime import datetime
hatasız bir şekilde yayınlayamıyorsanız yanlış ayarlanmış bir şey var . 2.3 sürümüne kadar bu iyi!
builtins
yerleşik modülleri değil, yerleşik işlevleri ve sınıfları listeler (cf. docs.python.org/3/tutorial/modules.html#the-dir-function ). Listede istiyorsanız yerleşik modüllerin , do import sys; print(sys.builtin_module_names)
(Bkz docs.python.org/3/library/sys.html#sys.builtin_module_names ).
Adlandırılmış dosyalar __init__.py
diskteki dizinleri Python paketi dizinleri olarak işaretlemek için kullanılır. Dosyalara sahipseniz
mydir/spam/__init__.py
mydir/spam/module.py
ve mydir
senin yolunda, sen kod alabilirsiniz module.py
olarak
import spam.module
veya
from spam import module
__init__.py
Dosyayı kaldırırsanız , Python artık bu dizinin içinde alt modülleri aramaz, bu nedenle modülü içe aktarma girişimleri başarısız olur.
__init__.py
Dosyası genellikle boş, ancak, örneğin, yukarıda verilen vb daha uygun adı, tutma kolaylığı fonksiyonları altında paketin seçilen kısımlarını vermek için kullanılabilir, init modülünün içeriği olarak erişilebilir
import spam
dayalı bu
__init__.py
Python 2.X altında gerekliydi ve yine de Python 2.7.12 (test ettim) altında gerekli ancak artık (iddia edildiği gibi) Python 3.3'ten itibaren gerekli değil ve Python 3.4.3 (I test etti). Daha fazla bilgi için stackoverflow.com/questions/37139786 adresine bakın.
__init__.py
.
setup.py
ve kullanırsanız , her dizinde find_packages()
olması gerekir __init__.py
. Bkz. Stackoverflow.com/a/56277323/7127824
Python paket olarak bir dizin etiketleme ve tanımlamanın yanı sıra __all__
, __init__.py
paket düzeyinde herhangi değişken tanımlamak için izin verir. Bir paket, API benzeri bir şekilde sık sık içe aktarılacak bir şey tanımlarsa bunu yapmak genellikle uygundur. Bu model Pythonic "düz iç içe olandan daha iyi" felsefesine bağlılığı teşvik eder.
İşte benim projelerimden bir örnek, hangi sık sık benim veritabanımı ile etkileşim için bir sessionmaker
çağrı ithal Session
. Birkaç modül içeren bir "veritabanı" paketi yazdım:
database/
__init__.py
schema.py
insertions.py
queries.py
Benim __init__.py
aşağıdaki kodu içerir:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
Session
Burada tanımladığımdan , aşağıdaki sözdizimini kullanarak yeni bir oturum başlatabilirim. Bu kod, "veritabanı" paket dizininin içinden veya dışından yürütülürken kullanılanla aynıdır.
from database import Session
session = Session()
Tabii ki, bu küçük bir kolaylıktır - alternatif, Session
veritabanı paketimdeki "create_session.py" gibi yeni bir dosyada tanımlamak ve aşağıdakileri kullanarak yeni oturumlar başlatmak olacaktır:
from database.create_session import Session
session = Session()
Burada uygun kullanımları kapsayan oldukça ilginç bir reddit ipliği __init__.py
var:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
Çoğunluk __init__.py
, "açık, örtükten daha iyidir" felsefesini ihlal etmemek için dosyaların çok ince olması gerektiği görüşündedir.
engine
, sessionmaker
, create_engine
Ve os
tüm ayrıca alınabilir database
o ad alanının bir karmaşa yaptık gibi şimdi ... görünüyor.
__all__ = [...]
içe aktarılanları sınırlamak için kullanabilirsiniz import *
. Ama bunun dışında, evet, dağınık bir üst düzey ad alanına bırakıldınız.
Bunun 2 ana nedeni var __init__.py
Kolaylık sağlamak için: diğer kullanıcıların işlevlerinizin paket hiyerarşisinde tam yerini bilmesi gerekmez.
your_package/
__init__.py
file1.py
file2.py
...
fileN.py
# in __init__.py
from file1 import *
from file2 import *
...
from fileN import *
# in file1.py
def add():
pass
o zaman diğerleri tarafından add ()
from your_package import add
file1 bilmeden,
from your_package.file1 import add
Bir şeyin başlatılmasını istiyorsanız; örneğin, günlük kaydı (en üst düzeye konulması gerekir):
import logging.config
logging.config.dictConfig(Your_logging_config)
__init__.py
bazen yararlı olabilir, ancak her zaman değil.
__init__.py
Dosya modül olarak bunu içeren Python tedavi dizinleri yapar.
Ayrıca, bu bir modüle yüklenecek ilk dosyadır, bu nedenle modülü her yüklendiğinde çalıştırmak istediğiniz kodu yürütmek veya dışa aktarılacak alt modülleri belirlemek için kullanabilirsiniz.
Python 3.3 olduğundan __init__.py
, dizinleri içe aktarılabilir Python paketleri olarak tanımlamak artık gerekli değildir.
PEP 420'yi kontrol edin : Örtülü Ad Alanı Paketleri :
__init__.py
İşaretçi dosyaları gerektirmeyen ve otomatik olarak birden çok yol parçasına yayılabilen paket dizinleri için yerel destek ( PEP 420'de açıklandığı gibi ad alanı paketlerine çeşitli üçüncü taraf yaklaşımlarından esinlenerek )
İşte test:
$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
referanslar:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
__init__. py Python 3 paketleri için gerekli değil mi?
Python'da paketin tanımı çok basittir. Java gibi, hiyerarşik yapı ve dizin yapısı aynıdır. Ama __init__.py
bir paket içinde olmalısın . __init__.py
Dosyayı aşağıdaki örnekle açıklayacağım :
package_x/
|-- __init__.py
|-- subPackage_a/
|------ __init__.py
|------ module_m1.py
|-- subPackage_b/
|------ __init__.py
|------ module_n1.py
|------ module_n2.py
|------ module_n3.py
__init__.py
mevcut olduğu sürece boş olabilir. Dizinin bir paket olarak görülmesi gerektiğini belirtir. Tabii ki, __init__.py
uygun içeriği de ayarlayabilirsiniz.
Module_n1 modülüne bir işlev eklersek:
def function_X():
print "function_X in module_n1"
return
Koşu sonrası:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
Sonra hiyerarşi paketini takip ettik ve module_n1 işlevini çağırdık. __init__.py
SubPackage_b'de şu şekilde kullanabiliriz :
__all__ = ['module_n2', 'module_n3']
Koşu sonrası:
>>>from package_x.subPackage_b import *
>>>module_n1.function_X()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named module_n1
Bu nedenle, * import kullanarak modül paketi __init__.py
içeriğe tabidir .
from package_x.subPackage_b.module_n1 import function_X
Python bir __init__.py
dosya olmadan çalışsa da yine de bir tane eklemelisiniz.
Bir paketin modül olarak ele alınması gerektiğini belirtir, bu nedenle paketini ekleyin (boş olsa bile).
Bir __init__.py
dosyayı gerçekten kullanabileceğiniz bir durum da vardır :
Aşağıdaki dosya yapısına sahip olduğunuzu düşünün:
main_methods
|- methods.py
Ve bunu methods.py
içeriyordu:
def foo():
return 'foo'
Kullanmak foo()
için aşağıdakilerden birine ihtiyacınız olacaktır:
from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()
Belki orada ( örneğin çalışma zamanları / bağımlılıklar) methods.py
içinde kalmanız gerekir (veya istersiniz main_methods
) ama sadece içe aktarmak istiyorsunuz main_methods
.
Eğer adını değiştirdiyseniz methods.py
için __init__.py
o zaman kullanabilirsiniz foo()
sadece ithal ederek main_methods
:
import main_methods
print(main_methods.foo()) # Prints 'foo'
Bu __init__.py
, paketin bir parçası olarak değerlendirildiği için çalışır .
Bazı Python paketleri aslında bunu yapar. Bir örnek ile JSON çalışan, import json
aslında ithal etmektedir __init__.py
dan json
(pakete burada paket dosyası yapısını görmek ):
Kaynak kodu:
Lib/json/__init__.py
__init__.py
içinde bulunduğu dizine yüklenebilir bir modül gibi davranacaktır.
Kod okumayı tercih eden insanlar için, İki Bit Simyacı'nın yorumunu buraya yazdım .
$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$
$ rm /tmp/mydir/spam/__init__.py*
$
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>>
Diğer python dosyalarının içe aktarılmasını kolaylaştırır. Bu dosyayı diğer py dosyalarını içeren bir dizine (şeyler söyleyin) yerleştirdiğinizde, import stuff.other gibi bir şey yapabilirsiniz.
root\
stuff\
other.py
morestuff\
another.py
__init__.py
Python, şeyler için kaynak kodunun nerede olduğunu bilmediğinden ve bir paket olarak tanıyamadığından, dizin öğeleri içinde bu olmadan , other.py dosyasını içe aktaramazsınız.
Bir __init__.py
dosya içe aktarmayı kolaylaştırır. Bir __init__.py
paket içinde bir varsa, işlev a()
dosyadan şu şekilde içe aktarılabilir b.py
:
from b import a
Ancak bu olmadan doğrudan içe aktaramazsınız. Sistem yolunu değiştirmeniz gerekir:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a