Seite 1 von 1

Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 08:57
von pymue
Hallo,

hab grad einen dicken Knoten im Kopf ... ich komme von der C++-Welt, daher wohl auch meine falsche Denke.

Wenn ich ein Projekt mit mehreren Dateien habe, macht es sicherlich Sinn, diese in einer gewissen Ordnerstruktur zu organisieren. Nun war meine Idee, dass alle Module in einem Unterordner abgelegt werden, und alle direkt ausführbaren Dateien auf der höchsten Ebene:

helloworld.py
subfolder
MyText.py -> enthält getMyText()
MyString.py -> enthält getMyString()

Um über helloworld.py eine Funktion aus MyText.py auszuführen, muss diese mit "from subfolder.MyText import getMyText" eingebunden werden. Bis hierhin ist auch alles klar.
Nun aber angenommen dass MyText.py auch noch MyString.py verwendet. Dann habe ich das Problem, dass je nachdem ob ich helloworld.py oder MyText.py ausführen möchte verschiedene Art und Weisen nötig sind, MyString einzubinden. Das Ausführen von helloworld.py erfodert in MyText.py "from subfolder.MyString import getMyString", das Ausführen von MyText.py (z.B. zum Test mit if __name__ == "__main__") erfordert jedoch "from MyString import getMyString".

Oder ist der Ansatz schlicht und einfach falsch?
Ich habe auch von dem __init__.py gelesen, dass wohl im subfolder enthalten sein sollte. Das geschilderte Problem lässt sich damit aber nicht lösen. ???

MfG pymue

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 09:09
von snafu
Es ist nicht schlimm, wenn zwei unterschiedliche Wege zum gleichen Objekt führen. Der eigentliche Import wird von Python dabei nur einmal durchgeführt. Das importierte Modul wird anschließend in ``sys.modules`` gecached und für nachfolgende Importe wiederverwendet.

Böse wird's erst bei zirkulären Abhängigkeiten, d.h. wenn Modul A etwas aus Modul B verwendet *und* Modul B etwas aus Modul A verwendet.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 09:14
von pymue
hmm, aber ich bekomme doch ein ImportError, wenn ich den falschen Weg verwende.

???

MfG pymue

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 09:20
von snafu
Du hast vorher von *unterschiedlichen* Wegen gesprochen und nichts von einem ``ImportError`` erwähnt. Dieser Fehler tritt naheliegenderweise auf, wenn du das Objekt auf eine falsche Art importiert hast. Das hat aber nichts mit der Tatsache zu tun, dass durchaus mehrere Import-Wege zum selben Ziel führen könnnen.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 09:29
von BlackJack
@pymue: Das Problem ist, dass Du anscheinend das Arbeitsverzeichnis zu dem Skript *in* dem Package wechselst. Das ist ein „no go” weil es eben genau zu diesen (und weiteren) Problemen führt. Wenn Du ``my_text.py`` als Skript ausführen möchtest, dann wechsle in das Verzeichnis in dem ``subfolder/`` liegt, oder sorge anderweitig dafür das ``subfolder/`` im Suchpfad für Importe liegt, und starte es mit ``./subfolder/my_text.py``, oder mit ``python -m subfolder.my_text``.

Lesestoff zur Schreibweise von Namen: Style Guide for Python Code.

``subfolder`` ist hier ja nur ein Beispiel, aber ich erwähne trotzdem mal dass das Teil des Packages ist, also einen vernünftigen Namen braucht der als Modulname Sinn macht. Und eventuell mag man auch etwas Code in dieses Package/Modul stecken, also zum Beispiel `__version__` und `__author__`. Wenn die öffentliche API nicht zu umfangreich ist, wird die auch oft über das Package zur Verfügung gestellt, damit Benutzer nicht die anderen Module importieren müssen.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 09:30
von snafu
Wie lautet denn der Fehler? Kann es sein, dass du gerade Module und Packages durcheinander wirfst? Denn Packages brauchen durchaus die von dir bereits ins Spiel gebrachte ``__init__.py``, damit sie funktionieren.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 09:56
von pymue
es ist sehr gut möglich, dass ich grad etwas durcheinander bringe ...

... anders gefragt. Ich habe drei Dateien: "helloworld.py", "MyText.py" und "MyString.py". Die letzten beiden befinden sich in einem Unterordner "subfolder".

helloworld.py:

Code: Alles auswählen

from subfolder import MyText

print(MyText.getStr())
MyText.py:

Code: Alles auswählen

import MyString

def getStr():
    return MyString.getMyString()

if __name__ == "__main__":
    print(getStr())
MyString.py:

Code: Alles auswählen

def getMyString():
    return "This is my String"
Wie muss ich nun die Import-Zeilen gestalten, damit helloworld.py und MyText.py gleichzeitig ausführbar sind?
Vielleicht noch zu den Begriffen. "helloworld.py", "MyText.py" und "MyString.py" sind Module. Der Unterordner mit den zugehörigen Dateien ist ein Package. Richtig?

MfG pymue

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 10:06
von cofi
Ja, "subfolder" ist ein package. Aber nur, wenn es auch eine Datei namens "__init__.py" gibt: https://docs.python.org/2/tutorial/modu ... l#packages

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 10:23
von BlackJack
@pymue: Ich habe im Grunde ja schon geschrieben was man machen muss, bzw. was man nicht machen darf. Zusätzlich: Pakete innerhalb eines Packages würde ich über den Packagenamen importieren, also im `my_text`-Modul ein ``from subfolder import my_string``.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 10:42
von MagBen
pymue hat geschrieben:Wie muss ich nun die Import-Zeilen gestalten, damit helloworld.py und MyText.py gleichzeitig ausführbar sind?
Damit ein package oder ein Modul gefunden wird, reicht es nicht, dass in jedem package Ordner eine __init__.py Datei ist. Das root-Verzeichnis der ganzen package-Verzeichnisse muss auch in der Umgebungsvariablen PYTHONPATH drin sein.

Ausführbar heißt, Du gehst mit einer Shell in das entsprechende Verzeichnis und in diesem Verzeichnis rufst Du dann
> python helloworld.py
auf und in subfolder rufst Du
> python MyText.py
auf.

Überlege Dir auch gut, ob Du wirklich in jedem Modul so ein
if __name__ == "__main__":
Konstrukt brauchst. Wieviel main-Funktionen brauchst Du in Deinen C++ Projekten?

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 10:51
von BlackJack
@MagBen: Um Himmels willen *Nein*. Man führt keine Module in Packages aus in dem man das Arbeitsverzeichnis dort hin wechselt! Das Arbeitsverzeichnis ist auch Teil des Suchpfads, und zwar vor allen anderen, und damit sind alle Module *im* Package auch direkt ohne das Package importierbar, was zu Namenskollisionen führen kann und falschen Modulen die importiert werden. Wir hatten neulich gerade so einen Fall hier bei dem dann immer die falschen Module importiert wurden. Das kann man in eigenem Quelltext noch durch absolute Importe in den Griff bekommen, aber bei fremden Bibliotheken fällt ein Import *dort* auf die Nase.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 11:04
von pymue
@BlackJack: Deine Antwort hatte ich ganz übersehen. Ich hab mir schon gedacht, dass es auf das Arbeitsverzeichnis ankommt.
Aber dennoch gibt es ja sicherlich irgendwann einmal Abhängigkeiten innerhalb eines Packages. Wie werden die dann "verlinkt"? ... hmmm, wenn man sowieso immer von aussen testet (in dem ordner der subfolder enthält), dann müssen sich die Module selbst ja gar nicht gegenseitig kennen. Richtig?

P.S. Dieses 'if __name__ == "__main__": ' habe ich bis jetzt zum debuggen verwendet, d.h. um kleine Funktionen zu testen.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 11:05
von MagBen
BlackJack hat geschrieben:@MagBen: Um Himmels willen *Nein*. Man führt keine Module in Packages aus in dem man das Arbeitsverzeichnis dort hin wechselt! Das Arbeitsverzeichnis ist auch Teil des Suchpfads, und zwar vor allen anderen, und damit sind alle Module *im* Package auch direkt ohne das Package importierbar, was zu Namenskollisionen führen kann und falschen Modulen die importiert werden. Wir hatten neulich gerade so einen Fall hier bei dem dann immer die falschen Module importiert wurden. Das kann man in eigenem Quelltext noch durch absolute Importe in den Griff bekommen, aber bei fremden Bibliotheken fällt ein Import *dort* auf die Nase.
Dann eben im Root-Verzeichnis
> python helloworld.py
und
> python subfolder/MyText.py
Wird aber ziemlich sperrig bei sub-sub-sub-foldern.
Deshalb meinte ich, nicht überall muss eine Main-Funktion rein.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 11:17
von kbr
pymue hat geschrieben:P.S. Dieses 'if __name__ == "__main__": ' habe ich bis jetzt zum debuggen verwendet, d.h. um kleine Funktionen zu testen.
Das ist anfänglich auch völlig ok. Obgleich das __main__ Konstrukt eigentlich nur in Modulen vorkommen sollte, die für sich selbst ein lauffähiges Programm darstellen, deren Funktionen aber auch in andere Programme integrierbar sein sollen. Zum Testen solltest Du Dich später dann mit Unittests oder pytest vertraut machen.

Re: Projektorganisation

Verfasst: Dienstag 14. Oktober 2014, 23:08
von snafu
Ausführbare Module sollte man besser via ``python -m package.subpackage.modul`` aus dem Pfad starten, dessen Unterverzeichnis das oberste Package bildet. Dann findet Python schon von sich aus den richtigen Weg zum gewünschten Modul. Selbst in Shell-Skripten würde ich diese Art des Aufrufs bevorzugen.

Und für Skripte, die nur die ``main()``-Funktion eines Python-Programms aufrufen sollen, würde ich einfach eine ausführbare Datei in einem gesonderten Verzeichnis außerhalb der Package-Hierarchie erstellen, die das Package importiert und ``main()`` aus dem passenden Modul aufruft. Zumindest unter Linux funktioniert das mit dem passenden Shebang ohne Probleme.