İyi / doğru paket __init__.py dosyalarını nasıl yazarım


188

Paketim aşağıdaki yapıya sahiptir:

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
   ...

__init__.pyDosyaların nasıl doğru yazılması gerektiğinden emin değilim . Bakışlar ister:
__init__.py #1

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

Ama örneğin nasıl görünmeli __init__.py #2? Benimki:

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

Ne zaman __all__kullanılmalı?


3
Kodda import * kullanmanın genellikle çok kötü bir uygulama olduğunu ve mümkünse kaçınılması gerektiğini unutmayın. Bunun için çok az iyi kullanım durumu vardır, ancak bunlar çok nadirdir.
Mayou36

PSA: iyi ad alanı paketlerini (yeni tür paket) nasıl yazacağınızı öğrenmek istiyorsanız, şu örnek pakete göz atın
Kyle

Yanıtlar:


146

__all__çok iyi - modülleri otomatik olarak içe aktarmadan içe aktarma ifadelerini yönlendirmeye yardımcı olur http://docs.python.org/tutorial/modules.html#importing-from-a-package

kullanmak __all__ve import *gereksizdir, sadece __all__gereklidir

Ben import *bir __init__.pyithalat paketleri kullanmak için en güçlü nedenlerinden biri var varolan bir uygulama kırmadan birden fazla komut dosyası haline geldi bir komut dosyası refactor edebilmek olduğunu düşünüyorum. Ama en başından beri bir paket tasarlıyorsanız. Sanırım __init__.pydosyaları boş bırakmak en iyisidir .

Örneğin:

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

o zaman uygulama büyür ve şimdi bütün bir klasör

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

init betiği

__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

böylece aşağıdakileri yapmak için yazılan bir komut dosyası değişiklik sırasında bozulmaz:

from foo import fooFactory, tallFoo, shortFoo

3
' Hepsi ' ve satır satır içe aktarma konusunda çok kafam karıştı . Örneğin çok aydınlatıcı.
Junchen

2
Ben " __all__ve import *gereksiz" ile karıştırıyorum __all__, modülün tüketici from foo import *tarafından kullanılır ve modül kendisi tarafından başkalarını kullanmak için kullanılır ....
Nick T

using __all__ and import * is redundant, only __all__ is needed Bunlar nasıl gereksiz? Farklı şeyler yaparlar.
endolit

113

Kendi __init__.pydosyalarım daha sık boş. Özellikle, ben asla bir from blah import *parçası olarak __init__.py- "paketi alma" doğrudan paketin bir parçası olarak tanımlanan her türlü sınıf, fonksiyonlar vb almak anlamına gelirse, o zaman ben içeriği yerine blah.pypaketin içine lexically kopyalamak __init__.pyve kaldırmak blah.py( burada kaynak dosyaların çoğaltılması iyi değildir).

import *Deyimleri (eek) desteklemede ısrar ederseniz , __all__(minik olarak, içine sahip olabileceğiniz gibi bir isim listesi kullanmak ) hasar kontrolüne yardımcı olabilir. Genel olarak, ad alanları ve açık ithalat iyi şeylerdir ve kavramlardan birini veya her ikisini atlayarak sistematik olarak atlamaya dayanan herhangi bir yaklaşımı yeniden düşünmenizi şiddetle tavsiye ederim! -)


9
Şahsen, şeyleri ayrı tutmayı ve sonra içe aktarmayı * tercih ederim. Bu nedenle, katlama ve diğer şeylere rağmen, ilgili olsa bile, çok fazla sınıf içeren dosyalara göz atmaktan nefret ediyorum.
Stefano Borini

5
@ stefano büyük bir çerçeve düşünün. eğer kullanırsa import *, asla kullanamayacağınız özellikleri bile tüm çerçeveyi koşulsuz olarak kabul etmelisiniz. __init__.pyboş tutmak , sadece ya hep ya anlamsız olmaktan daha fazla şans verir. bükülmüş düşünmek.
mg.

ithalat mobilescouter sonra bile boş tutmak, hala mobilescouter.mapper veya mobilescouter.vehicle veya mobilescouter.whatever kullanamazsınız. ithalat mobilescouter.A değil, mobilescouter.B ..... çok ayrıntılı değil mi?
sunqiang

6
@ sunqiang bu kişisel ama sanmıyorum. from mobilescouter import A, Bsadece bir kod satırı ve 666 sınıf ve her birinin kendi dosyası olan bir projeniz yok, değil mi? import *kodunuzda iki veya daha fazla varsa ad alanını potansiyel çöplerle dolduruyorsunuz ve nereden Ageldiğini çabucak unutacaksınız . Üst paket de aynısını yaparsa? tüm alt paketleri ve alt alt paketleri alıyorsunuz. Python'un dediği gibi, açık, örtük olmaktan iyidir.
mg.

1
@mg, init .py dosyasında "import A, B" satırı varsa , sözdizimi ile A (veya B) çağırabilirim: mobilescouter.A; "mobilescouter import A, B" den kullanırsak, bu sadece A.something. Bazen sadece bu satır, A'nın mobilescouter'ın bir alt paketi olduğunu hatırlamıyorum ve bunun ad alanı kirliliğine katkıda bulunduğunu düşünüyorum (mobilescouter import * "dan" "çok daha iyi olmasına rağmen. Tekdüzen ortak arayüz. init .py ithalat alt_pkgname şeyler yapmak.
sunqiang

1

Sizin __init__.pybir olmalıdır docstring'ini .

Tüm işlevler modüllerde ve alt paketlerde uygulansa da, paket doktrininiz nereden başlayacağınızı belgeleyeceğiniz yerdir. Örneğin, python emailpaketini düşünün . Paket belgeleri, paketin içindeki çeşitli bileşenlerin birlikte, amacını, arka planını ve nasıl çalıştığını açıklayan bir giriş niteliğindedir. Sfenks veya başka bir paket kullanarak docstrings'den otomatik olarak dokümantasyon oluşturursanız, docstring paketi böyle bir girişi tanımlamak için tam olarak doğru yerdir.

Diğer içerikler için firecrow ve Alex Martelli'nin mükemmel yanıtlarına bakın .


Gerçek mu __init__.pyiçin emailpaketin bu kılavuz takip? "Paket içindeki çeşitli bileşenlerin birlikte nasıl çalıştığını" açıklamak için fazla bir şey yapmayan tek satırlı bir doktora görüyorum.
Gertlex

@Gertlex Belki sadece web dokümantasyonunda.
gerrit
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.