Python uygulaması için en iyi proje yapısı nedir? [kapalı]


730

Python'da önemsiz olmayan bir son kullanıcı masaüstü (web değil) uygulaması geliştirmek istediğinizi düşünün. Projenin klasör hiyerarşisini yapılandırmanın en iyi yolu nedir?

Arzu edilen özellikler bakım kolaylığı, IDE dostu olma, kaynak kontrolü dallanma / birleştirme için uygunluk ve kolay kurulum paketleri oluşturmadır.

Özellikle:

  1. Kaynağı nereye koydunuz?
  2. Uygulama başlangıç ​​komut dosyalarını nereye koyarsınız?
  3. IDE projesini nereye koydunuz?
  4. Ünite / kabul testlerini nereye koyarsınız?
  5. Yapılandırma dosyaları gibi Python dışı verileri nereye koyarsınız?
  6. Pyd / so ikili uzantı modülleri için C ++ gibi Python dışı kaynakları nereye koyarsınız?

Yanıtlar:


378

Çok önemli değil. Seni ne mutlu ederse çalışacak. Çok aptalca kural yok çünkü Python projeleri basit olabilir.

  • /scriptsveya /binbu tür komut satırı arayüzleri için
  • /tests testlerin için
  • /lib C dili kitaplıklarınız için
  • /doc çoğu dokümantasyon için
  • /apidoc Epydoc tarafından oluşturulan API dokümanları için.

Üst düzey dizin README, Config ve neyi içerebilir.

Zor seçim, bir /srcağaç kullanılıp kullanılmayacağıdır . Python arasında bir ayrım yoktur /src, /libve/bin Java veya C gibi vardır.

Üst düzey bir /srcdizin bazıları tarafından anlamsız göründüğünden, üst düzey dizininiz uygulamanızın üst düzey mimarisi olabilir.

  • /foo
  • /bar
  • /baz

Tüm bunları "ürünümün adı" dizinine koymanızı öneririm. Bu nedenle, adlı bir uygulama yazıyorsanız quux, tüm bunları içeren dizin adlandırılır /quux .

Diğer proje var PYTHONPATH, o zaman içerebilir /path/to/quux/fooyenidenQUUX.foo modülü .

Benim durumumda, Komodo Edit kullandığım için, IDE cuft tek bir .KPF dosyası. Aslında bunu üst düzey /quuxdizine koydum ve SVN'ye eklemeyi ihmal ettim.


23
Dizin yapısını taklit etmenizi tavsiye edeceğiniz herhangi bir açık kaynak python projesi?
Lance Rushing

4
İyi bir örnek için Django'ya bakın.
S.Lott

33
Django'yu iyi bir örnek olarak görmüyorum - sys.path ile hileler oynamak kitabımda anlık bir DQ.
Charles Duffy

18
re "tricks": Django, kök proje klasörünün üst öğesini sys.path'e ekler, böylece modüller "project.app.module import klass" veya "app.module import klass" dan içe aktarılabilir.
Jonathan Hartley

3
Oh, bu numarayı seviyorum ve şimdi kullanıyorum. Paylaşılan modülü başka bir dizine koymak istiyorum ve modülü sistem genelinde yüklemek istemiyorum ya da insanlardan PYTHONPATH'ı manuel olarak değiştirmelerini istemiyorum. İnsanlar daha iyi bir şey önermedikçe, bence bu aslında en temiz yol.
Yongwei Wu

242

Jean-Paul Calderone'nin bir Python projesinin Dosya Sistemi yapısına göre :

Project/
|-- bin/
|   |-- project
|
|-- project/
|   |-- test/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |   
|   |-- __init__.py
|   |-- main.py
|
|-- setup.py
|-- README

23
Project/project/? Ah, ikincisi paket adı.
Cees Timmerman

44
bin klasöründeki yürütülebilir dosya proje modülüne nasıl başvuruyor? (Python sözdiziminin ../bir include deyiminde izin verdiğini düşünmüyorum )
ThorSummoner

8
@ThorSummoner Basit. Paketi siz yüklersiniz! ( pip install -e /path/to/Project)
Kroltan

22
Birisi bu düzenin bir örneğini hello.py ve hello-test.py ile sıkıştırır ve bize yeni başlayanlar için hazır hale getirirse harika olurdu.
jeremyjjbrown

8
@Bloke Çekirdek, -epaketi düzenlenebilir bir paket olarak yükleyen, yani gerçek proje klasörüne bağlantılar olarak yükleyen işarettir . Yürütülebilir dosya daha sonra sadece import projectmodüle erişebilir.
Kroltan

232

Jean-Paul Calderone tarafından yazılan bu blog yazısı genellikle #python'da Freenode'da bir cevap olarak verilmiştir.

Bir Python projesinin dosya sistemi yapısı

Yapmak:

  • dizine projenizle ilgili bir ad verin. Örneğin, projeniz "Twisted" olarak adlandırılmışsa, kaynak dosyaları için en üst düzey dizini adlandırın Twisted. Eğer bültenleri yaptığınızda, bir sürüm numarası soneki içermelidir: Twisted-2.5.
  • bir dizin oluşturun Twisted/binve varsa yürütülebilir dosyalarınızı buraya koyun. Onlara bir.pyPython kaynak dosyaları olsalar bile uzantı . Projelerinizde başka bir yerde tanımlanan bir ana işlevin içe aktarılması ve çağrılması dışında bunlara kod koymayın. (Hafif kırışıklık: Windows'da yorumlayıcı dosya uzantısı tarafından seçildiğinden, Windows kullanıcılarınız aslında .py uzantısını isterler. Bu nedenle, Windows için paketlediğinizde, eklemek isteyebilirsiniz. Ne yazık ki kolay dağıtım hilesi yoktur. Bu işlemi otomatikleştirmeyi biliyorum.PICIX'te .py uzantısının sadece bir siğil olduğunu düşünürken, Windows'ta eksiklik gerçek bir hatadır, kullanıcı tabanınız Windows kullanıcılarını içeriyorsa, sadece .py'ye sahip olmayı tercih edebilirsiniz. her yerde uzantı.)
  • Projeniz tek bir Python kaynak dosyası olarak ifade edilebilirse, dizine koyun ve projenizle ilgili bir ad verin. Örneğin Twisted/twisted.py,. Birden fazla kaynak dosyaya ihtiyacınız varsa, bunun yerine bir paket oluşturun ( Twisted/twisted/boş Twisted/twisted/__init__.py) ve kaynak dosyalarınızı bu dosyaya yerleştirin. Örneğin Twisted/twisted/internet.py,.
  • birim testlerinizi paketinizin bir alt paketine koyun (not - yukarıdaki tek Python kaynak dosyası seçeneğinin bir hile olduğu anlamına gelir - birim testleriniz için her zaman en az bir dosyaya ihtiyacınız vardır). Örneğin Twisted/twisted/test/,. Tabii ki, ile bir paket yapın Twisted/twisted/test/__init__.py. Testleri gibi dosyalara yerleştirin Twisted/twisted/test/test_internet.py.
  • kendinizi iyi hissediyorsanız, sırasıyla yazılımınızı ekleyin Twisted/READMEve Twisted/setup.pyaçıklayın ve yükleyin.

Yapma:

  • kaynağınızı srcveya adlı bir dizine yerleştirin lib. Bu, kurulum yapmadan çalışmayı zorlaştırır.
  • testlerinizi Python paketinizin dışına koyun. Bu, kurulu bir sürümde testlerin yapılmasını zorlaştırır.
  • yalnızca bir __init__.pykod içeren bir paket oluşturun ve tüm kodunuzu içine koyun __init__.py. Paket yerine bir modül yapın, daha basit.
  • Python'un, kullanıcının onu içeren dizini kendi ithalat yoluna eklemesine gerek kalmadan (PYTHONPATH veya başka bir mekanizma yoluyla) Python'un modülünüzü veya paketinizi içe aktarabilmesini sağlamak için büyülü hackler bulmaya çalışın. Sen olacak değil doğru bütün davalarını ve yazılım çevrelerindeki çalışmadığında kullanıcıların Sana kızgın alacak.

25
Tam da ihtiyacım olan buydu. "DONT, Python'un modülünüzü veya paketinizi, kullanıcının onu içeren dizini kendi içe aktarma yoluna eklemesine gerek kalmadan içe aktarabilmesini sağlamak için sihirli hack'lerle gelmeye çalışın." Bunu bildiğim iyi oldu!
Jack O'Connor

1
Şey, bu bir projenin nereye yerleştirileceği önemli doktor bölümünden bahsetmiyor.
lpapp

14
"Kaynağınızı src veya lib adlı bir dizine koyun. Bu, yüklemeden çalıştırılmasını zorlaştırır." Ne kurulur? Soruna neden olan dizin adı mı yoksa alt dizin olması mı?
Peter Ehrlich

4
"Bazı insanlar testlerinizi modülünüzün içinde dağıtmanız gerektiğini söyleyecektir - katılmıyorum. Bu genellikle kullanıcılarınız için karmaşıklığı artırır; birçok test paketi genellikle ek bağımlılıklar ve çalışma zamanı bağlamları gerektirir." python-guide-pt-br.readthedocs.io/en/latest/writing/structure/...
Endolit

2
"Bu, yüklemeden çalıştırmayı zorlaştırır." - mesele bu
Nick T

123

Python Projesini Doğru Kaynakla Açık Kaynak Bulma'ya göz atın .

Bu mükemmel makalenin proje düzeni bölümünü alıntılayayım :

Bir proje kurarken, düzenin (veya dizin yapısının) doğru olması önemlidir. Akla yatkın bir düzen, potansiyel katkıda bulunanların sonsuza kadar bir kod parçası için avlamak zorunda kalmadıkları anlamına gelir; dosya konumları sezgiseldir. Mevcut bir projeyle uğraştığımız için, muhtemelen bazı şeyleri hareket ettirmeniz gerekeceği anlamına gelir.

En baştan başlayalım. Çoğu projede bir dizi üst düzey dosya vardır (setup.py, README.md, gereksinimleri.txt vb.). O zaman her projenin sahip olması gereken üç dizin vardır:

  • Proje belgelerini içeren bir dokümanlar dizini
  • Gerçek Python paketini depolayan projenin adıyla adlandırılan bir dizin
  • İki yerden birinde bir test dizini
    • Test kodu ve kaynakları içeren paket dizininin altında
    • Tek başına bir üst düzey dizin olarak Dosyalarınızın nasıl organize edilmesi gerektiği konusunda daha iyi bir fikir edinmek için, projelerimden birinin düzeninin basitleştirilmiş bir görüntüsü olan sandman:
$ pwd
~/code/sandman
$ tree
.
|- LICENSE
|- README.md
|- TODO.md
|- docs
|   |-- conf.py
|   |-- generated
|   |-- index.rst
|   |-- installation.rst
|   |-- modules.rst
|   |-- quickstart.rst
|   |-- sandman.rst
|- requirements.txt
|- sandman
|   |-- __init__.py
|   |-- exception.py
|   |-- model.py
|   |-- sandman.py
|   |-- test
|       |-- models.py
|       |-- test_sandman.py
|- setup.py

Gördüğünüz gibi, bazı üst düzey dosyalar, bir docs dizini (oluşturulan sfenks oluşturulan belgeleri koyacağı boş bir dizindir), bir sandman dizini ve sandman'ın altında bir test dizini vardır.


4
Bunu yapıyorum ama daha çok: Virtualenv env otomatikleştiren bir 'env' hedefi olan bir üst düzey Makefile var; ./env/bin/pip install -r gereksinimleri.txt; ./env/bin/python setup.py gelişir 've genellikle env'ye bağlı olan ve ayrıca test bağımlılıklarını yükleyen ve daha sonra py.test çalıştıran bir' test 'hedefi.
pjz

@pjz Fikrinizi genişletebilir misiniz? MakefileAynı seviyeye koymaktan mı bahsediyorsun setup.py? Eğer doğru make envbir şekilde yeni bir yaratma otomatize anlamak venvve paketleri içine yüklerseniz ...?
St.Antario

@ St.Antario tam olarak. Belirtildiği gibi, genellikle testleri çalıştırmak için bir 'test' hedefim ve bazen geçerli etikete bakan ve bir tekerlek oluşturan ve bunu pypi'ye gönderen bir 'serbest bırakma' hedefim var.
pjz


19

Projeyi python_boilerplate şablonunu kullanarak başlatmayı deneyin . Büyük ölçüde en iyi uygulamaları takip eder (örneğin buradakiler ), ancak projenizi bir noktada birden fazla yumurtaya bölmeye istekli olmanız durumunda daha uygundur (ve inan bana, en basit projeler dışında herhangi bir şeyle, yapacaksınız. ortak durum, başka birinin kütüphanesinin yerel olarak değiştirilmiş bir sürümünü kullanmanız gerektiğidir).

  • Kaynağı nereye koydunuz?

    • Oldukça büyük projeler için, kaynağı birkaç yumurtaya bölmek mantıklıdır. Her yumurta ayrı bir kurulum araçları düzeni olarak giderdi PROJECT_ROOT/src/<egg_name>.
  • Uygulama başlangıç ​​komut dosyalarını nereye koyarsınız?

    • İdeal seçenek, uygulama başlangıç ​​komut dosyasının entry_pointyumurtalardan birinde kayıtlı olmasıdır .
  • IDE projesini nereye koydunuz?

    • IDE'ye bağlıdır. Birçoğu PROJECT_ROOT/.<something>projenin kökeninde eşyalarını saklıyor ve bu iyi.
  • Ünite / kabul testlerini nereye koyarsınız?

    • Her yumurtanın PROJECT_ROOT/src/<egg_name>/testsdizininde tutulan ayrı bir test seti vardır . Şahsen py.testonları çalıştırmak için kullanmayı tercih ederim .
  • Yapılandırma dosyaları gibi Python dışı verileri nereye koyarsınız?

    • Değişir. Farklı tipte Python olmayan veriler olabilir.
      • "Kaynaklar" , yani bir yumurta içinde paketlenmesi gereken veriler. Bu veriler, paket ad alanında bir yerde karşılık gelen yumurta dizinine gider. pkg_resourcesPaket üzerinden setuptoolsveya Python 3.7'den beriimportlib.resources standart kitaplığı modülün.
      • "Config-files" , yani proje kaynak dosyalarının harici olduğu düşünülen, ancak uygulama çalışmaya başladığında bazı değerlerle başlatılması gereken Python olmayan dosyalar. Geliştirme sırasında bu dosyaları saklamayı tercih ederim PROJECT_ROOT/config. Dağıtım için çeşitli seçenekler olabilir. Windows'da %APP_DATA%/<app-name>/config, Linux /etc/<app-name>veya /opt/<app-name>/config.
      • Oluşturulan dosyalar , yani yürütme sırasında uygulama tarafından oluşturulabilen veya değiştirilebilen dosyalar. PROJECT_ROOT/varGeliştirme sırasında ve /varLinux dağıtımı sırasında onları içeride tutmayı tercih ederim .
  • Pyd / so ikili uzantı modülleri için C ++ gibi Python dışı kaynakları nereye koyarsınız?
    • içine PROJECT_ROOT/src/<egg_name>/native

Belgeler tipik olarak PROJECT_ROOT/docveya içine girer PROJECT_ROOT/src/<egg_name>/doc(bu, bazı yumurtaların ayrı büyük projeler olarak görülüp görülmediğine bağlıdır). Bazı ek yapılandırma PROJECT_ROOT/buildout.cfgve gibi dosyalarda olacaktır PROJECT_ROOT/setup.cfg.


Harika bir cevap için teşekkürler! Benim için birçok şeyi açıkladın! Sadece bir sorum var: Yumurtalar yuvalanabilir mi?
Shookie

Hayır, yumurtaları .egg dosyalarını diğer .egg dosyaları içinde saklamak ve bunun [gerçekten garip bir şeye sahip olmadığınız sürece] çok faydalı olacağını umarak "yuvalayamazsınız". Bununla birlikte, "sanal" yumurtalar - yararlı kod sağlamayan, ancak bağımlılık listelerindeki diğer paketleri listeleyen boş paketler oluşturabilirsiniz. Bu şekilde, kullanıcı böyle bir paket kurmaya çalıştığında, birçok bağımlı yumurtayı tekrar tekrar kuracaktır.
KT.

@KT Oluşturulan verileri nasıl ele aldığınız hakkında biraz ayrıntı verebilir misiniz? Özellikle, geliştirme (kodlama) ve geliştirme arasındaki farkı nasıl ayırt edersiniz? Bir base_data_locationdeğişkeniniz olduğunu düşünüyorum, ama bunu nasıl uygun şekilde ayarlıyorsunuz?
cmyr

1
"Çalışma zamanı verileri" hakkında konuştuğunuzu varsayıyorum - insanların genellikle / var / packagename veya ~ / .packagename / var altına koyacağı bir şey var. Çoğu zaman bu seçenekler varsayılan olarak kullanıcılarınızın değiştirmeyi umursamayacağı kadar yeterlidir. Bu davranışın ayarlanmasına izin vermek istiyorsanız, seçenekler oldukça bol ve tek bir hepsine uyan en iyi uygulama olduğunu düşünmüyorum. Tipik seçenekler: a) ~ / .packagename / configfile, b) MY_PACKAGE_CONFIG = / path / to / configfile dosyasını dışa aktar c) komut satırı seçenekleri veya işlev parametreleri d) bunların kombinasyonunu verir.
KT.

Sizin için en sevdiğiniz yapılandırma yükleme mantığını işleyen ve belki de kullanıcının çalışma zamanında ayarları değiştirmesine izin veren tek bir Config sınıfına sahip olmanın normal olduğunu unutmayın. Genel olarak, olsa da, bu ayrı bir soru (burası daha önce bir yerde sorulmuş olabilir) değerinde bir sorun olduğunu düşünüyorum.
KT.

15

Deneyimlerime göre, bu sadece bir yineleme meselesi. Verilerinizi ve kodunuzu gittikleri her yere koyun. Şansınız, yine de yanılıyorsunuz. Ancak, işlerin nasıl şekilleneceğine dair daha iyi bir fikir edindikten sonra, bu tür tahminler yapmak için çok daha iyi bir konumdasınız.

Uzantı kaynaklarına göre, trunk altında python için bir dizin ve diğer çeşitli diller için bir dizin içeren bir Kod dizinimiz var. Şahsen, bir dahaki sefere herhangi bir uzantı kodunu kendi havuzuna koymaya çalışıyorum.

Bununla birlikte, ilk noktama geri dönüyorum: bundan çok büyük bir anlaşma yapmayın. Sizin için işe yarayan bir yere koyun. Eğer işe yaramayan bir şey bulursanız, değiştirilebilir (ve değiştirilmelidir).


Evet. Bu konuda "Pythonic" olmaya çalışın: açık örtük daha iyidir .. Dizin heirarchies yazıldığından daha fazla okunur / denetlenir. Etc ..
eric

10

Python dışı veriler, kurulum araçlarındakipackage_data destek kullanılarak Python modülleriniz içinde en iyi şekilde paketlenir . Şiddetle tavsiye ettiğim bir şey, birden çok projenin kullanabileceği paylaşılan ad alanları oluşturmak için ad alanı paketleri kullanmaktır - paketler koymak için Java kuralı gibi (ve paylaşılan bir ad alanına sahip olabilmek gibi ).com.yourcompany.yourprojectcom.yourcompany.utils

Yeniden dallanma ve birleştirme, yeterince iyi bir kaynak kontrol sistemi kullanırsanız, yeniden adlandırmalarla bile birleşmeleri yönetir; Çarşı bu konuda özellikle iyi.

Burada diğer bazı cevapların aksine, ben srcüst düzey bir dizin (+ ile docve testyanında dizinleri) sahip +1 . Dokümantasyon dizin ağaçları için özel kurallar kullandığınız şeye bağlı olarak değişecektir; Sfenks , örneğin, hızlı başlangıç ​​aracının desteklediği kendi kurallarına sahiptir.

Lütfen, lütfen kurulum araçlarından ve pkg_resources'dan yararlanın; bu, diğer projelerin kodunuzun belirli sürümlerine güvenmesini (ve kullanıyorsanız birden fazla sürümün farklı kod olmayan dosyalar ile aynı anda yüklenmesini) kolaylaştırır package_data.

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.