__İnit__.py için kod ekleniyor


85

Django'daki model sistemin nasıl çalıştığına bir göz atıyorum ve anlamadığım bir şey fark ettim.

__init__.pyGeçerli dizinin bir paket olduğunu belirtmek için boş bir dosya oluşturduğunuzu biliyorum . Ve içeri __init__.pyaktarmanın * düzgün çalışması için bazı değişkenler ayarlayabilirsiniz .

Ancak django, bir grup from ... import ... ifadesi ekler ve içinde bir grup sınıf tanımlar __init__.py. Neden? Bu sadece işleri dağınık göstermiyor mu? Bu kodun girilmesini gerektiren bir sebep var mı __init__.py?


13
Bu gerçekten Django ile ilgili değil, değil mi? Evet, ilk olarak Django'da gördünüz, ancak bu daha çok saf bir Python şeyine benziyor - belki Django etiketi gerçekten uygun değil.
S.Lott

__init__.pyDjango 1.8'de herhangi bir ithalat ifadesi göremiyorum . Bu daha eski bir sürüm için miydi? öyleyse hangi versiyon?
Gobi Dasu

Yanıtlar:


72

İçerisindeki tüm içe __init__.pyaktarmalar, onu içeren paketi (dizini) aldığınızda kullanılabilir hale gelir.

Misal:

./dir/__init__.py:

import something

./test.py:

import dir
# can now use dir.something

DÜZENLEME: belirtmeyi unuttum, bu __init__.pydizinden herhangi bir modülü ilk kez içe aktardığınızda kod çalışır. Bu nedenle, normalde herhangi bir paket düzeyinde başlatma kodunu koymak için iyi bir yerdir.

EDIT2: dgrant, örneğimdeki olası bir karışıklığa dikkat çekti. In __init__.py import something, paketten gerekli olmayan herhangi bir modülü içe aktarabilir. Örneğin, bunun yerine koyabiliriz import datetime, ardından en üst seviyemizde test.pybu snippet'lerin ikisi de çalışacaktır:

import dir
print dir.datetime.datetime.now()

ve

import dir.some_module_in_dir
print dir.datetime.datetime.now()

Sonuç __init__.pyolarak, içeri aktarılan modüller, işlevler veya sınıflar olsun, içinde atanan tüm adlar , paketi veya paketteki bir modülü içe aktardığınızda paket ad alanında otomatik olarak kullanılabilir.


Tamam teşekkürler. Ama hala sınıfları eklemenin neden iyi bir fikir olacağından emin değilim, __init__.py bu sınıfların ilklendirme kodunu gerçekten dikkate almıyorum (ama belki de bu konuda yanılıyorum).
Erik

Bunlar muhtemelen paketle her çalıştığınızda yararlı olan sınıflardır. Ama spekülasyon yapmak istemiyorum, objektif olsun ya da olmasın orada olmalarının birçok nedeni olabilir :)
Alexander Kojevnikov

13
Bu aynı zamanda tarihsel nedenlerle de olabilir. Modülü pakete dönüştürdüğünüzde, module.py'yi module / __ init__.py'ye dönüştürdüğünüzde, mevcut tüm kodlar onu eskisi gibi kullanabilir, ancak artık modülde alt modüller olabilir.
Łukasz

1
Modüller ebeveyni __init__.pyörtük olarak yürütür . İçerideki modülleri içe aktararak, __init__.pydöngüsel içe aktarmalar oluşturursunuz. Bu __init__.pytür bir içe aktarmadan önce tam olarak çalıştırılmayacaktır. __init__.pyBoş tutmak daha güvenlidir .
Ivo Danihelka

Bunun __init__.pydosyalara özgü olmadığını belirtmek önemlidir . Sizin gibi bir dir/other.pyşey içeren bir dosyanız from datetime import datetimeolsaydı, dir.other.datetime.now()hatta arayabilirdiniz from dir.other import datetime.
Carles Sala

37

Bu gerçekten kişisel bir tercihtir ve python modüllerinizin düzeni ile ilgilidir.

Diyelim ki adlı bir modülünüz var erikutils. Orada bir modül olabilir iki yolu vardır, ya sen adlı bir dosya var erikutils.py sizinle ilgili şu sys.pathveya bir dizin olarak adlandırılan sahip erikutils Aşağıdaki yerlerde de sys.pathboş ile __init__.pyiçindeki dosyada. O zaman aradığınız modüllerin bir grup var diyelim fileutils, procutils, parseutilsve o altındaki alt modüller olmak istiyorum erikutils. Bazı .py adı verilen dosyaları yapmak Yani fileutils.py , procutils.py ve parseutils.py :

erikutils
  __init__.py
  fileutils.py
  procutils.py
  parseutils.py

Belki sadece değil aittir yapmak birkaç işlevlere sahip fileutils, procutilsya da parseutilsmodüllerin. Ve diyelim ki adında yeni bir modül oluşturmak istemiyorsunuz miscutils. VE işlevi şu şekilde çağırabilmek istiyorsunuz:

erikutils.foo()
erikutils.bar()

yapmak yerine

erikutils.miscutils.foo()
erikutils.miscutils.bar()

Yani erikutilsmodül bir dosya değil dizin olduğu için, onun işlevlerini __init__.pydosyanın içinde tanımlamamız gerekiyor .

Django'da aklıma gelen en iyi örnek django.db.models.fields. TÜM django * Field sınıfları __init__.py, django / db / models / fields dizinindeki dosyada tanımlanır . Sanırım bunu yaptılar çünkü her şeyi farazi bir django / db / models / fields.py modeline sığdırmak istemediler , bu yüzden onu birkaç alt modüle ( örneğin related.py , files.py ) ayırdılar ve yapılan * Alan tanımlarını alanlar modülünün kendisine yapıştırdılar (dolayısıyla, __init__.py).


1
dgrant, demek istediğim bu somethingharici bir modül olabilir , yani bir şey işe yarayacak. Yorumunuz için teşekkürler, daha net hale getirmek için gönderimi düzenleyeceğim.
Alexander Kojevnikov

29

__init__.pyDosyayı kullanmak, iç paket yapısını dışarıdan görünmez hale getirmenizi sağlar. Dahili yapı değişirse (örneğin, bir fat modülünü ikiye böldüğünüz için), yalnızca __init__.pydosyayı ayarlamanız gerekir , ancak pakete bağlı olan kodu ayarlamazsınız . Ayrıca ambalajınızın parçalarını, örneğin genel kullanım için hazır değillerse görünmez yapabilirsiniz.

delKomutu kullanabileceğinizi unutmayın , bu nedenle tipik bir __init__.pyşuna benzeyebilir:

from somemodule import some_function1, some_function2, SomeObject

del somemodule

Şimdi bölmeye karar verirseniz somemodule, yenisi __init__.pyşunlar olabilir:

from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject

del somemodule1
del somemodule2

Dışarıdan bakıldığında paket aynen eskisi gibi görünüyor.


1
@Arlen: Konu, genel API'nin bir parçası olmaması. Bir modülü yeniden adlandırırsanız, hiçbir bağımlı kodun bozulmayacağından emin olabilirsiniz. Ek olarak bu, API öğelerinin yalnızca bir kez görünmesini sağlar, örneğin, API belgelerini otomatik olarak oluşturmak için iç gözlem kullanıldığında.
nikow

5
@Arlen: Bir modülü silmek, bir modülü import <pack>.somemodule1doğrudan engelleyecektir . Yalnızca <pack>kendi __init__.pyve silinmemiş alt modüllerinde tanımlanan veya içe aktarılan nesnelerden içe aktarabilirsiniz .
MestreLion
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.