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
Projektorganisation
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.
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.
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.
@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.
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.
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.
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:
MyText.py:
MyString.py:
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
... 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())
Code: Alles auswählen
import MyString
def getStr():
return MyString.getMyString()
if __name__ == "__main__":
print(getStr())
Code: Alles auswählen
def getMyString():
return "This is my String"
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
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
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
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
@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``.
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.pymue hat geschrieben:Wie muss ich nun die Import-Zeilen gestalten, damit helloworld.py und MyText.py gleichzeitig ausführbar sind?
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?
@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.
@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.
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.
Dann eben im Root-VerzeichnisBlackJack 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.
> 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.
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.pymue hat geschrieben:P.S. Dieses 'if __name__ == "__main__": ' habe ich bis jetzt zum debuggen verwendet, d.h. um kleine Funktionen zu testen.
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.
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.