Aufbau von Python-Projekten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Sandor
User
Beiträge: 5
Registriert: Dienstag 29. September 2020, 20:03

Hallo,

ich habe eine sehr allgemeine Frage zur Projektstruktur von Python / Pycharm. In einem größeren Projekt wird der Code ja auf mehrere Dateien aufgeteilt. Das gleiche habe ich auch mit meinem Projekt vor. Nun bin ich mir unsicher, wie diese Dateien miteinander "verknüpft" werden. Ich habe bereits ein Computerspiel programmiert, allerdings in Blitzmax. Dort musste ich eine "main-Datei" deklarieren, und in diese Main-Datei habe ich alle anderen Dateien importiert. Das ging ziemlich einfach durch den Befehl "Include" (zB "Include gamelogic.bmx"). Das gleiche habe ich jetzt mit meiner main-Datei gemacht:

Code: Alles auswählen

from Include import logic
from Include import loadsave
from Include import types
Somit kann ich zB in meiner Main-Datein folgende Funktion aufrufen:

Code: Alles auswählen

logic.UIstart()
Was mich jetzt irritiert, ist, dass ich bei den anderen Dateien (zB in logic.py) ebenfalls die anderen Dateien importieren muss, damit ich sie nutzen kann. Auch muss ich in jeder Datei pygame neu importieren. Das verwirrt mich etwas, denn in meiner Vorstellung importiere ich in der main-Datei alle Dateien aus dem Ordner include, und kann die Funktionen und Klassen dieser Dateien dann überall anwenden, und auch pygame, das ich ja in der main importiere, in allen anderen Dateien ansprechen. Ich bin mir sicher, dass ich das wohl ziemlich falsch mache, eventuell muss ich Pycharm irgendwie sagen, dass diese geladenen Dateien zum Projekt gehören? Daher würde ich mich sehr über Hinweise zum korrekten Aufbau von Python-Projekten in Pycharm sehr freuen.
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sandor: Was man in einem Modul verwenden will muss man dort auch irgendwie definieren, also entweder tatsächlich dort definieren, oder die Objekte aus einem anderen Modul importieren oder zumindest das Modul importieren und über das Modul auf die Objekte zugreifen. Es gibt keine ”projektglobalen” Definitionen die automagisch überall bekannt wären ausser den eingebauten Funktionen/Datentypen.

Und das ist auch gut so, weil es damit übersichtlicher bleibt und gleiche Namen in verschiedenen Modulen kein Problem sind. Zumindest solange man nicht mit Sternchen-Importen anfängt, was man aus genau diesen Gründen nicht macht.

Die Namen in Deinem Beispiel halten sich nicht alle an die Konventionen. Modul- und Packagenamen werden klein geschrieben, und inhaltlich ist `Include` kein sinnvoller Name. Ansonsten werden Namen in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). `UIstart()` sollte also `ui_start()` heissen, beziehungsweise besser `start_ui()`, ausser Du bist Yoda. 😉

Die Funktion ist einem Modul das `logic` heisst allerdings etwas komisch, denn man trennt üblicherweise die Geschäftslogik von der Benutzeroberfläche, also sollte ein `start_ui()` eher nicht in der Logik vorkommen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sandor
User
Beiträge: 5
Registriert: Dienstag 29. September 2020, 20:03

__blackjack__ hat geschrieben: Donnerstag 31. Dezember 2020, 01:27 @Sandor: Was man in einem Modul verwenden will muss man dort auch irgendwie definieren, also entweder tatsächlich dort definieren, oder die Objekte aus einem anderen Modul importieren oder zumindest das Modul importieren und über das Modul auf die Objekte zugreifen. Es gibt keine ”projektglobalen” Definitionen die automagisch überall bekannt wären ausser den eingebauten Funktionen/Datentypen.

Und das ist auch gut so, weil es damit übersichtlicher bleibt und gleiche Namen in verschiedenen Modulen kein Problem sind. Zumindest solange man nicht mit Sternchen-Importen anfängt, was man aus genau diesen Gründen nicht macht.
Danke dir, mit Blitzmax hatte ich den Vorteil, dass ich meinen Code auf verschiedene Module aufteilen konnte, einfach der Übersichtlichkeit halber. Dann musste ich wie gesagt im "Main-Modul" einfach alle anderen Module einmalig importieren und konnte so in jedem Modul sämtliche Funktionen einfach aufrufen, selbst ohne anzugeben, in welchem Modul sich die Funktion befindet. Dadurch konnte ich jeden Namen nur einmal vergeben, stimmt, aber das ist doch einfacher, als acht mal den gleichen Namen zu haben, oder? Ich empfand das als sehr intuitiv, und bei 120.000 Zeilen Code auch recht übersichtlich.

Mit Python läuft das wohl anders. Ich dachte, ich könnte meinen Code in verschiedene Module packen, die einigermaßen in sich stimmig sind (Spiellogik, Graphisches, Spielstand laden/speichern, ich hatte sogar einfach ein Modul mit all meinen Klassen (was in Blitzmax "types" heißt, daher der Name hier)). Ich sehe noch nicht den Vorteil, die Funktionen und Klassen so stark "getrennt" zu haben, man wird doch immer in einem Modul die Funktionen und Klassen eines anderen Moduls brauchen, bzw. ansprechen müssen, sonst würde man doch gar nicht so viele verschiedene Module einbinden, und könnte stattdessen einfach ein "riesiges Modul" haben, mit allen Klassen und Funktionen für das Game.

Jetzt weiß ich aber auch, nach was ich suchen muss: Ich wusste nicht, dass auch die reinen Textdateien, in denen ich meinen Quellcode schreibe, Module heißen (Ich habe mir Module als abgekapselt vorgestellt, dass ich dort nur schwer den Code ändern kann, bzw. dieses nicht vorgesehen ist, und quasi nur fertige Module genutzt werden).

Wegen Konventionen: Hast Recht, ich werde mich künftig daran halten!
nezzcarth
User
Beiträge: 1764
Registriert: Samstag 16. April 2011, 12:47

Sandor hat geschrieben: Donnerstag 31. Dezember 2020, 09:08 Jetzt weiß ich aber auch, nach was ich suchen muss: Ich wusste nicht, dass auch die reinen Textdateien, in denen ich meinen Quellcode schreibe, Module heißen .
Falls noch nicht geschehen, bietet es sich vielleicht an, das offizielle Python-Tutorial (https://docs.python.org/3/tutorial/index.html) mal durch zu arbeiten. Da werden Module sowie der Unterschied zu Packages erläutert.

Python-Module sind eigenständige, für sich stehende Einheiten mit einem eigenen Namespace. Eine einzelne Python-Datei kann schon ein vollständiges Programm bzw. eine Bibliothek sein. Eine Hierarchie zwischen Modulen gibt es in dem Sinne nicht (Packages mal außen vor). Da ein Modul also sowohl autonom funktionieren, als auch von beliebigen anderen Modulen aufgerufen werden können soll, ist ja gar nicht vorhersehbar, woher nun zum Beispiel pygame kommen soll, wenn es nicht genau in dem Modul, das es benötigt, definiert ist. Unter diesem Gesichtspunkt ist das Konzept von Python-Modulen vielleicht etwas besser nachvollziehbar,
Sandor
User
Beiträge: 5
Registriert: Dienstag 29. September 2020, 20:03

nezzcarth hat geschrieben: Donnerstag 31. Dezember 2020, 09:43 Falls noch nicht geschehen, bietet es sich vielleicht an, das offizielle Python-Tutorial (https://docs.python.org/3/tutorial/index.html) mal durch zu arbeiten. Da werden Module sowie der Unterschied zu Packages erläutert.

Python-Module sind eigenständige, für sich stehende Einheiten mit einem eigenen Namespace. Eine einzelne Python-Datei kann schon ein vollständiges Programm bzw. eine Bibliothek sein. Eine Hierarchie zwischen Modulen gibt es in dem Sinne nicht (Packages mal außen vor). Da ein Modul also sowohl autonom funktionieren, als auch von beliebigen anderen Modulen aufgerufen werden können soll, ist ja gar nicht vorhersehbar, woher nun zum Beispiel pygame kommen soll, wenn es nicht genau in dem Modul, das es benötigt, definiert ist. Unter diesem Gesichtspunkt ist das Konzept von Python-Modulen vielleicht etwas besser nachvollziehbar,
Danke, ja ist nun für mich besser nachvollziehbar. Ich bin noch in der alten Denkweise von Blitzmax drin. Ja, das Tutoral habe ich angefangen, ich bin jedoch eher der Typ, der am "lebenden Objekt" lernen möchte, ich habe da einfach mehr Motivation. Ich möchte Teil 2 meines Games in Python schreiben und sofort anfangen, und am Anfang steht dann ja die Architektur des Projekts. Ich arbeite Tutorials eher selektiv durch, zB jetzt alles über Module. Wie gesagt, ich dachte Module wären in erster Linie dazu gedacht, nicht verändert zu werden, und "nur" sofort zu nutzen, aber das trifft wohl eher auf externe Bibliothek zu. zB der Absatz hat mir sofort geholfen: https://py-tutorial-de.readthedocs.io/d ... dules.html und jetzt wird es auch klarer.
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sandor: Das Tutorial in der Python-Dokumentation sind Grundlagen, die sollte man *vorher* durcharbeiten. Wenn man grundsätzlich schon Programmieren kann, ist das auch relativ schnell gemacht. Und es ist am lebenden Objekt, denn viele Beispiele dort sind für die interaktive Python-Shell, können also ”live” nachvollzogen werden. Was man auch mit den ganzen Beispielen machen sollte — also nicht einfach nur passiv das Tutorial lesen, sondern das alles auch ausprobieren, ein bisschen verändern, schauen ob das passiert was man erwartet hat, und falls nicht herausfinden warum nicht.

Bei 120k Zeilen ist es alles andere als übersichtlich wenn die auf mehrere Dateien aufgeteilt sind, das alles letztlich aber in *einem* Namensraum landet. Wenn man da eine Datei mit 1.000 Zeilen im Editor offen hat, muss man ja trotzdem immer wissen was in den anderen 11.000 Zeilen, die man gerade nicht sieht steht, an Namen existiert um die a) verwenden zu können, und b) keinen Namen mehrfach zu definieren.

Module trennt man nach Themen, nicht nach Typen. Also nicht alle Funktionen und alle Klassen/Datentypen in verschiedene Module, sondern Konstanten, Funktionen, und Klassen die thematisch zusammengehören, werden in jeweils einem Modul zusammengefasst. Das ergibt dann am Ende normalerweise auch weniger Importe in den einzelnen Modulen.

Ich persönlich fange oft tatsächlich nur mit einem Modul an und erst wenn das zu umfangreich wird, schaue ich welche Teile sich sinnvoll in einem oder mehreren anderen Modulen zusammenfassen lassen. Wobei wenn ein Modul nicht mehr ausreicht bei mir als erstes ein Package entsteht wo das dann alles drin landet. Mit dem Inhalt des ursprünglichen Moduls als `__main__.py`, damit das Package wie ein Programm ausführbar ist.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten