Module in Python

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
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Hallo,

ich bin derzeit dabei mein Python Prgramm zu modularisieren.
Ich nutze Pycharme auf Win 7.

Ich habe verschiedene Pythonfiles, die in unterschiedlichen Ordnern liegen, die dann aufgerufen werden sollen, um das Programm besser lesbar zu machen.

Konkret sieht das gaze so aus:
Main-Ordner-A
-----Sub-Ordner B
----------Python-Modul 1
----------Python Modul 2
-----Python Modul 3

Ich möchte nun im dritten Pythonmodul die beiden anderen Module verweden. also:

modul3 hat am anfang import B.modul2 und B.modul1
modul2 jedoch braucht zum funktionieren modul1, und wenn ich mein modul3 jetzt ausführe sagt er, dass "No module named modul1" existiert.

Ich hoffe das war nicht zu verwirrend; falls das zu allgemein forumliert war, kann ich gerne konkreter werden.


Viele Dank für die Hilfe
Ewkos
BlackJack

@Ewkos: Wenn Du zirkuläre Importe machst, oder versuchst zu machen, denn das ist ziemlich tricky überhaupt richtig hinzubekommen, dann ist die Aufteilung auf Module ziemlich sicher falsch.
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Hi, also ein Zirkelaufruf habe ich nicht.

Modul 3 verwendet Modul 1 und 2 und Modul 2 nutzt Modul 1.
Ich konnte es nun lösen, indem ich bei Modul 2 folgendes verwende:
from . import module1

Damit kann ich Modul 2 leider nur noch importiert verwenden und nicht mer allein; gibt es auch dafür eine Lösung?
BlackJack

@Ewkos: Wenn Du keinen Kreis in den Abhängigkeiten hast, dann verstehe ich das Problem nicht. Und ich verstehe auch nicht wieso Du `module2` nicht ”allein” verwenden kannst?

Ich denke Du machst da etwas falsch. Kann es sein das Du das nicht sauber als Package verwendest sondern versuchst Module *in* einem Package als Programme auszuführen ohne über das Package zu gehen? Und beim Importieren vielleicht das gleiche: Teile innerhalb eines Packages gleichzeitig im Pfad für Python-Module zu verwenden, führt zu Chaos und ist so nicht vorgesehen.
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Bei mir sieht es nun so aus:

### /module3.py
import B.module2

### /B/module2.py
from . import module1

### /B/module1.py
# macht iwas

So funktioinert dann modul3 korrekt, aber so ist modul 2 nicht mehr ausführbar.
Das ersteres funktioniert, liegt daran, dass das file im aktuellen ordner gescuht werden soll, wenn modul 2 aufgerufen wird, aber falls ich modul 2 allein verwenden will, ist dieser "." unnötig und ich könnte ganz normal import modul 1 schreiben.
BlackJack

@Ewkos: Du machst das wie schon gesagt falsch. Du kannst und solltest nicht `module2` ausführen, denn `module2` gibt es gar nicht. Das ist Teil des Packages `B`. Und so kann und muss man das dann auch ausführen als `B.module2`. Python hat da die Option `-m` für, also ``python -m B.module2 …``. Und dabei sollte man auch auf keinen Fall als aktuelles Arbeitsverzeichnis ``…/B/`` haben, denn das sind die Module im Package `B` entweder nur oder sogar gleichzeitig direkt und über das Package importierbar, was falsch ist und zu lustigen Effekten führen kann, die man nicht haben möchte.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Ewkos: als Hauptprogramm ausgeführte Module können keine relativen Importe vornehmen. In Python3 (ab 3.6) führt dies zu einem ImportError, bei früheren Version sind die Fehlermeldungen andere (SystemError etc.).

Ein Workaround in Python 3.6 wäre das folgende in module2:

Code: Alles auswählen

try:
    from . import module1
except ImportError:
    import module1
BlackJack

@kbr: Das wäre aber falsch, weil es ja a) weiter die Probleme hat das plötzlich Module über mehr als einen Weg importierbar sind, und alles auf gleicher Ebene, also die Module/Packages *in* dem Package plötzlich auf der obersten Ebene als Importe zur Verfügung stehen, was auch wieder Probleme bereiten kann wenn die den gleichen Namen wie beispielsweise ein Modul aus der Standardbibliothek haben. Und b) gibt es ja mit der ``-m``-Option einen offiziellen Weg Module in Packages als Programme auszuführen. Und dabei treten diese Probleme nicht auf.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: das kann man durchaus machen umgerade gezielt dafür zu sorgen, dass Module über mehr als einen Weg importierbar sind. Es ist in der Situation aber sicher richtig sich zu fragen, ob ein berechtigter Spezialfall vorliegt oder das Problem eher auf einen Entwurffehler hindeutet (was meistens der Fall sein dürfte). Abgesehen davon sehen die import-header unschön aus – allein das wäre schon ein Grund für jeden Python-Ästheten sowas möglichst zu vermeiden. :wink:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Soweit ich das sehe, geht es nicht um zirkularen Import, der auch einfach zu machen wäre.
Sondern wenn man von einem Unterverzeichnis importieren will, muss man vorher dort eine leere Datei namens '__init__.py' anlegen.

Wenn sich zwei Module gegenseitig importieren müssen, dann geht das auch einfach. Das eine Modul import das andere zu Beginn, das andere dieses ganz am Ende. Das geht aber nur, wenn beim anderen Modul Referenzen auf etwas im einen Modul nur innerhalb von Funktionen oder Methoden vorkommen, die nicht schon beim import aufgerufen werden.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: __init__.py ist bei Python 3 nicht mehr nötig. Importe sollten immer am Anfang der Datei stehen. Das ist auch bei zirkulären Importen - sollten sie denn wirklich nötig sein - der Fall.

@kbr: solcher Import-Wodoo sollte nie nötig sein, wenn man Packages so einsetzt, wie sie gedacht sind. Alles andere führt im besten Fall zu Namenschaos.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben: Importe sollten immer am Anfang der Datei stehen. Das ist auch bei zirkulären Importen - sollten sie denn wirklich nötig sein - der Fall.

@kbr: solcher Import-Wodoo sollte nie nötig sein, wenn man Packages so einsetzt, wie sie gedacht sind. Alles andere führt im besten Fall zu Namenschaos.
Das geht aber nicht. Hier ein Beispiel:

Code: Alles auswählen

import DynTkInter as tk
from tkinter import ttk as StatTtk

class Label(tk.GuiElement,StatTtk.Label):

    def __init__(self,myname=None,**kwargs):
        tk._initGuiElement(kwargs,StatTtk.Label,self,myname,"label")

Dieses Modul muss DynTkInter importieren, weil es Klassen von Klassen dort ableitet.
DynTkInter muss auch dieses Modul Importieren, weil dort abgefragt wrid ob ein PanedWindow nun ein eigenes PanedWindow (StatTkInter.PanedWindow) oder eines von diesem Modul ist (StatTtk.PanedWindow). So etwas kommt aber erst nach dem Import der Module vor. Daher kann das einfach dadurch gelöst werden, dass DynTkInter dieses Modul DynTtk am Ende importiert.

Ein Import am Anfang geht dagegen nicht. Würde DynTkInter das Modul DynTtk am Anfang importieren, und würde dann DynTtk auch DynTkInter am Anfang importieren, dann geht das nicht, weil der import von DynTkInter noch gar nicht abgeschlossen ist, sondern lediglich an der Stelle steht, wo der import von DynTtk stattfindet.

Man kann nur etwas importieren, wenn etwas noch nicht importiert wurde, oder wenn der import soweit abgeschlossen ist, soweit man das braucht. Normalerweise würde man es wohl bis zum Ende brauchen und daher den import ganz am Ende tun. Wäre auch übersichtlicher als mittendrin, auch wenn das eine Modul nicht alles vom anderen braucht.
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Danke erstmal für die bisherige Hilfe!

Also sollte ich Modul2 nicht seperat ausführen, ok.

Nochmal eine Frage:
Ich habe folgende Ordnerstruktur und möchte wieder importieren:

Main-Ordner
- Ordner A
--main.py
-Ordner B
--test.py

Nun möchte ich test.py in main.py verwenden. Wie muss ich importieren, um das zu erreichen?

Bisher mache ich das so, aber es funktioniert nicht:
import sys
sys.path.append(".")
from B import test

Nun erhalte ich den folgenden Fehler:
ImportError: No module named 'data'

Vielen Dank für die Hilfe!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: __init__.py ist bei Python 3 nicht mehr nötig.
Komisch, dass ich das bisher immer in Python3 gebraucht hatte. Vielleicht braucht man es ja mit python 3.6 nicht mehr?

@ewkos: Du musst in Deinen Unterverzeichnissen eine leere Datei namens __init__.py anlegen!
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: das gilt schon seit Python 3.0

@ewkos: ein Modul mit Namen data sehe ich auch nicht. Wenn Du main.py aufrufen willst, mußt Du das auch per `python -m A.main` machen.
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Danke für den Hinweis; den Fehler habe ich aus meinem Programm kopiert und vergessen es zu 'B' zu ändern.

Also der Fehler ist:
ImportError: No module named 'B'
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@ewkos: der aktuelle Pfad wird schon automatisch durchsucht, es ist also nicht nötig und auch nicht schön, sys.path zu verändern. Wichtig ist nur, dass Du Python aus dem Pfad "Main-Ordner" heraus aufrufst.
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Ok, vielleicht hätte ich für das Beispiel den Hauptordner anders bennen sollen; Ziel ist es schon, dass main.py in Ordner A ausgefüht werden soll und test.py in Ordner B liegt, welcher auf der gleichen Ebene wie Ordner A ist.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Ewkos: sauber ist es, wenn die zu importierenden Module im Python-Path zu finden sind, bzw. sich im gleichen Verzeichnis oder in Unterverzeichnissen der Position des Hauptprogramms befinden und dabei nicht mit Packages der Standard Library namentlich kollidieren. Dies lässt sich umgehen, wie ich in einem Beispiel gezeigt habe. Das kann man machen, aber es eröffnet die Möglichkeit zu neuen Problemen.
Ewkos
User
Beiträge: 7
Registriert: Samstag 22. April 2017, 00:23

Ok Problem ist nun gelöst, vielen Dank für all die Hilfe!
Antworten