Ogólnie rzecz biorąc, jak są zorganizowane projekty (Python)?
Jestem trochę zagubiony, jeśli chodzi o strukturyzację mojego projektu. Staram się uporządkować rzeczy w sposób, który ma sens, ale zawsze kończy się restrukturyzacją całości co najmniej dwa razy dziennie. Przyznaję, że moje projekty nie są zbyt duże, ale chciałbym nie musieć wszystko restrukturyzować i po prostu się na czymś osiedlić.
Opiszę mój obecny program, aby spróbować nadać sens rzeczom. Jest to program graficzny z zapleczem bazy danych do obliczania ceny żagle. Nie wszystko jest jeszcze napisane, ale użytkownik będzie mógł wybrać kategorię żagla i model z dwóch rozwijanych menu. W zależności od kombinacji Kategoria-model, program wyświetli checkboxes i spinboxes. Te pola wyboru i spinboxy, po zmianie, pobierają informacje z bazy danych i przedstawiają cenę za zaznaczenie tego pola lub posiadanie określonej liczby (np. powierzchni w metrach kwadratowych) w spinboxie.
W obecnej formie projekt wygląda następująco to:
COPYING
README.md
SailQt.pyw (Should program be called from here ...)
sailqt/
__init__.py (This holds a __version__ string)
SailQt.pyw (... or here?)
gui/
__init__.py
MainWindow.py (This needs access to a __version__ string)
MainWindow_rc.py
OptionsWidget.py
ui_MainWindow.py
ui_OptionsWidget.py
resources/
__init__.py
database.db
generate_gui.py
MainWindow.ui
MainWindow.qrc
OptionsWidget.ui
icons/
logo.png
Do dalszego wyjaśnienia. resources
przechowuje wszystkie .ui
pliki wykonane w Qt Designer. Są to pliki XML, które opisują GUI. Można je przekonwertować na Skrypty Pythona za pomocą narzędzia terminal, które wbudowałem w generate_gui.py
. To samo dotyczy plików .qrc
. generate_gui.py
umieszcza automatycznie wygenerowane pliki w folderze gui
z prefiksem ui_
lub sufiksem _rc
. {[9] } jest obecnie pusty, ale w końcu będzie używany do przechowywania cen i wszystkiego.
MainWindow.py
i OptionsWidget.py
są plikami Pythona, które przechowuj obiekty o tej samej nazwie, bez przyrostka .py
. MainWindow
trzyma OptionsWidget
na swojej powierzchni wyświetlacza. Oba obiekty używają odpowiednich plików ui
i rc
.
SailQt.pyw
jest plikiem, który tworzy instancję MainWindow
, mówi mu, aby się pokazał, a następnie mówi (Py)Qt, aby wszedł do jego pętli i przejął stamtąd. Jest to w zasadzie plik .exe
z wieloma aplikacjami graficznymi, ponieważ jest to mały plik, który uruchamia program.
Moim wstępnym przypuszczeniem było umieszczenie SailQt.pyw
wewnÄ…trz folderu sailqt
. Ale wtedy MainWindow.py
nagle potrzebował dostępu do __version__
string. Jedynym sposobem, w jaki mogłem dowiedzieć się, jak to osiągnąć, było przeniesienie SailQt.pyw
do folderu głównego mojego projektu i pozwolenie MainWindow.py
zaimportować sailqt.__version__
. Ale biorąc pod uwagę, że to był n-ty raz musiałem przetasować rzeczy i ponowić linie w większości plików, aby uwzględnić to małe przetasowanie, postanowiłem po prostu zapytać tutaj.
Moje pytania są dość jasne:
- W jaki sposób są ogólnie zorganizowane projekty Pythona? ten link pydoc był pomocny, ale wydaje mi się to bardziej modułem niż czymś, co jest faktycznie wykonywane przez użytkownika.
- czy dobrze zrozumiałem powyższą strukturę?
- punkty bonusowe za odpowiedź na to pytanie, ponieważ jest to trochę off-topic. Jak to możliwe, że mogę robić
import os
, a potem robić takie rzeczy jakos.system("sudo rm -rf /")
, ale nie mogę robić takich rzeczy jakimport sailqt
, a potem robićsailqt.gui.generate_gui.generate()
?
1 answers
Najpierw zajmijmy się ostatnim pytaniem, ponieważ jest ono najważniejsze jeśli chodzi o strukturyzację projektów Pythona. Gdy już ustalisz, jak poprawnie zaimportować import w ramach projektu, reszta stanie się znacznie łatwiejsza do rozwiązania.
Kluczową rzeczą do zrozumienia jest to, że katalog aktualnie uruchomionego skryptu jest automatycznie dodawany do start z sys.path
. Więc jeśli umieścisz swój main.py
skrypt (co aktualnie wywołujesz SailQt.pyw
) poza Twojego pakietu w katalogu najwyższego poziomu kontenera, zagwarantuje, że import pakietów będzie zawsze działał, bez względu na to, skąd skrypt jest wykonywany.
Więc minimalna struktura początkowa może wyglądać tak:
project/
main.py
package/
__init__.py
app.py
mainwindow.py
Teraz, ponieważ main.py
musi znajdować się poza najwyższego poziomu katalogu pakietów Pythona, powinien on zawierać tylko minimalną ilość kodu (wystarczającą do uruchomienia programu). Biorąc pod uwagę powyższą strukturę, oznaczałoby to niewiele więcej niż to:
if __name__ == '__main__':
import sys
from package import app
sys.exit(app.run())
Moduł app
zawierałby większość kodu niezbędnego do zainicjowania programu i skonfigurowania gui, który byłby zaimportowany w następujący sposób:
from package.mainwindow import MainWindow
I ta sama forma w pełni kwalifikowanego Oświadczenia importowego może być używana z dowolnego miejsca z pakietem. Tak więc, na przykład, z tą nieco bardziej skomplikowaną strukturą:
project/
main.py
package/
__init__.py
app.py
mainwindow.py
utils.py
dialogs/
search.py
Moduł search
może zaimportować funkcję z modułu utils
w następujący sposób:
from package.utils import myfunc
W sprawie szczególnej aby uzyskać dostęp do łańcucha __version__
: dla programu PyQt, możesz umieścić na górze modułu app
następujący tekst:
QtGui.QApplication.setApplicationName('progname')
QtGui.QApplication.setApplicationVersion('0.1')
A następnie uzyskaj dostęp do nazwy / wersji później w następujący sposób:
name = QtGui.qApp.applicationName()
version = QtGui.qApp.applicationVersion()
Inne problemy z bieżącą strukturą dotyczą głównie utrzymywania separacji między plikami kodu i plikami zasobów.
Po pierwsze: drzewo pakietów powinno zawierać tylko pliki kodu (np. Moduły Pythona). Pliki zasobów należą do katalogu projektu (tzn. poza pakiet). Po drugie: pliki zawierające kod wygenerowany Z zasobów (np. przez pyuic lub pyrcc) powinny prawdopodobnie trafić do osobnego podpakietu (dzięki temu narzędzie kontroli wersji łatwo je wykluczyć). Wynikałoby to z ogólnej struktury projektu, takiej jak ta:
project/
db/
database.db
designer/
mainwindow.ui
icons/
logo.png
LICENSE
Makefile
resources.qrc
main.py
package/
__init__.py
app.py
mainwindow.py
ui/
__init__.py
mainwindow_ui.py
resources_rc.py
Tutaj Makefile
(lub odpowiednik) jest odpowiedzialny za generowanie plików ui/ RC, kompilację modułów Pythona, instalację / odinstalowanie programu itp. Zasoby potrzebne przez program w runtime (taki jak plik bazy danych), będzie musiał być zainstalowany w standardowej lokalizacji, którą program wie, jak znaleźć (np. coś w rodzaju /usr/share/progname/database.db
w Linuksie). W czasie instalacji Makefile
będzie również musiał wygenerować wykonywalny skrypt bash (lub jego odpowiednik), który wie, gdzie znajduje się twój program i jak go uruchomić. Czyli coś w stylu:
#!/bin/sh
exec 'python' '/usr/share/progname/main.py' "$@"
Który oczywiście musiałby być zainstalowany jako /usr/bin/progname
(lub cokolwiek innego).
Na początku może się to wydawać sporym problemem, ale oczywiście główną korzyścią ze znalezienia struktury projektu, która działa dobrze, jest to, że można ją ponownie wykorzystać we wszystkich przyszłych projektach (i zacząć opracowywać własne szablony i narzędzia do konfigurowania i zarządzania tymi projektami).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-10 20:56:19