Seite 1 von 1
isinstance oder wie vergleicht man typen
Verfasst: Donnerstag 10. August 2017, 21:15
von calo
Hallo,
Ich stehe gerade auf dem Schlauch. Folgende zwei Skripte:
FEMesh.py:
Code: Alles auswählen
import AbqDraw
class Edge(object):
def __init__(self):
self.parent = None
self.label = None
self.nodes = None
def create_edge(self):
pass
#########################
if __name__ == '__main__':
print 'within FEMesh.py'
edge = Edge()
draw = AbqDraw.drawing()
draw.draw_edge(edge)
AbqDraw.py:
Code: Alles auswählen
import FEMesh
class drawing(object):
def __init__(self):
pass
def draw_edge(self, edge):
print isinstance(edge, FEMesh.Edge)
print type(edge)
print FEMesh.Edge
#########################
if __name__ == '__main__':
print 'within AbqDraw.py'
Wobei FEMesh.py gestartet wird und das zweite Skript lädt.
Bis vor kurzem war das noch eine Datei. Seit ich die zwei Klassen in eigenständige Dateien getrennt habe, funktioniert die Typenprüfung
isinstance() nicht mehr so wie ich will:
Code: Alles auswählen
print isinstance(edge, FEMesh.Edge) -> False
print type(edge) -> <class '__main__.Edge'>
print FEMesh.Edge -> <class 'FEMesh.Edge'>
Wie kann ich innerhalb von AbqDraw.py überprüfen, ob
edge eine Instanz von
FEMesh.Edge ist?
Re: isinstance oder wie vergleicht man typen
Verfasst: Donnerstag 10. August 2017, 21:40
von BlackJack
@calo: Wenn Du zwei Module hast die sich gegenseitig importieren, dann stimmt etwas mit der Aufteilung nicht. Dann gehören die ja offensichtlich so eng zusammen, dass sie sich gegenseitig brauchen. So ein zirkulärer Import kann noch ganz andere Probleme nach sich ziehen.
Re: isinstance oder wie vergleicht man typen
Verfasst: Freitag 11. August 2017, 08:40
von calo
Schade. Ich hatte gehofft die Skripte klein zu halten. Ich habe die beiden Skripte wieder zusammengeführt. So funktioniert es natürlich. Das große Skript ist allerdings schon relativ groß (>2000 Zeilen)

.
Vielen Dank.
Re: isinstance oder wie vergleicht man typen
Verfasst: Freitag 11. August 2017, 09:15
von Zizibee
@calo: Kannst du das Skript nicht an anderer Stelle trennen? Also zum Beispiel eine Datei für die Klassen und dann jeweils eine für den zugehörigen Code von AbqDraw und FEMesh?
Re: isinstance oder wie vergleicht man typen
Verfasst: Freitag 11. August 2017, 09:46
von Sirius3
@calo: Du darfst Deine Module schon aufteilen, nur eben in einer Form, dass ein Abhängigkeitsbaum ensteht und kein Netz. Die Klasse drawing (sollte eigentlich Drawing heißen) ist abhängig von Edge. Dann darf in der Datei, in der die Klasse Edge definiert ist keine Abhängigkeit zu drawing existieren.
In Deinem Beispiel ist die Lösung also ganz einfach:
Code: Alles auswählen
# FEMesh.py
class Edge(object):
def __init__(self):
self.parent = None
self.label = None
self.nodes = None
def create_edge(self):
pass
Code: Alles auswählen
# AbqDraw.py
import FEMesh
class Drawing(object):
def __init__(self):
pass
def draw_edge(self, edge):
print isinstance(edge, FEMesh.Edge)
print type(edge)
print FEMesh.Edge
def main():
edge = FEMesh.Edge()
draw = Drawing()
draw.draw_edge(edge)
if __name__ == '__main__':
main()
Re: isinstance oder wie vergleicht man typen
Verfasst: Freitag 11. August 2017, 10:00
von snafu
Eine spezielle Anmerkung zum Code: Wenn eine __init__() nur aus pass besteht, dann kann man sie auch weglassen...
Re: isinstance oder wie vergleicht man typen
Verfasst: Freitag 11. August 2017, 13:28
von BlackJack
Ergänzend dazu: Wenn dann aber keine `__init__()` eine Basisklasse etwas sinnvolles macht um das Objekt zu initialisieren, `object.__init__()` macht da ja eigentlich nichts, dann riecht die Klasse sehr komisch.
Und ich hoffe das sind nicht wirklich zwei Klassen mit jeweils um die 1000 Zeilen Code.
Edit: Typprüfung ist bei einer objektorientierten Lösung ja auch bereits ein „code smell“. Das kann in einigen Fällen sinnvoll sein, aber auch ein Zeichen das der OOP-Entwurf nicht gut ist.
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 04:24
von Alfons Mittelmeyer
calo hat geschrieben:
Bis vor kurzem war das noch eine Datei. Seit ich die zwei Klassen in eigenständige Dateien getrennt habe, funktioniert die Typenprüfung
isinstance() nicht mehr so wie ich will:
Code: Alles auswählen
print isinstance(edge, FEMesh.Edge) -> False
print type(edge) -> <class '__main__.Edge'>
print FEMesh.Edge -> <class 'FEMesh.Edge'>
Wie kann ich innerhalb von AbqDraw.py überprüfen, ob
edge eine Instanz von
FEMesh.Edge ist?
Welche Klasse Edge meinst Du denn? Die, welche im Modul FEMesh.py definiert wird, oder diejenige welche dann in Deinem Mainscript definiert wird. Das sind zwei verschiedene Klassen Edge.
Beides müssen Module sein, sonst geht es nicht. Du mußt also ein Scrcipt haben, welches FEMesh importiert.
Also ein Startscript:
FEMesh.py
Code: Alles auswählen
import AbqDraw
class Edge(object):
def __init__(self):
self.parent = None
self.label = None
self.nodes = None
def create_edge(self):
pass
def main():
print 'within FEMesh.py'
edge = Edge()
draw = AbqDraw.drawing()
draw.draw_edge(edge)
Und AbqDraw.py kann so bleiben, wie es ist.
Das war kein Problem kreuzweise Kopplung sondern Unterschied zwischen Mainscript und Modul
Es gibt aber noch eine andere Möglichkeit
Verfasst: Samstag 12. August 2017, 09:42
von Alfons Mittelmeyer
Es gibt noch eine andere einfache Möglichkeit.
AbqDraw.py
Code: Alles auswählen
class Some_Class:
Edge = None
FEMesh = Some_Class()
class drawing(object):
def __init__(self):
pass
def draw_edge(self, edge):
print isinstance(edge, FEMesh.Edge)
print type(edge)
print FEMesh.Edge
#########################
if __name__ == '__main__':
print 'within AbqDraw.py'
FEMesh.py
Code: Alles auswählen
import AbqDraw
class Edge(object):
def __init__(self):
self.parent = None
self.label = None
self.nodes = None
def create_edge(self):
pass
AbqDraw.FEMesh.Edge = Edge
#########################
if __name__ == '__main__':
print 'within FEMesh.py'
edge = Edge()
draw = AbqDraw.drawing()
draw.draw_edge(edge)
Dabei ist natürlich FEMesh.py als Mainscript zu starten
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 09:53
von Sirius3
@Alfons Mittelmeyer: was Du da veranstaltest ist nicht einfach, sondern einfach nur unsinnig. Natürlich kann man alles so hinbiegen, dass es irgendwie funktioniert, aber das wird niemals ein klar strukturiertes, wartbares oder testbares Programm. Kreuzimporte sind immer ein Zeichen dafür, dass man sich bei der Aufteilung in Module nicht genug Gedanken gemacht, bzw. das Problem noch nicht völlig verstanden hat.
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 09:56
von Alfons Mittelmeyer
Sirius3 hat geschrieben:@Alfons Mittelmeyer: was Du da veranstaltest ist nicht einfach, sondern einfach nur unsinnig. Natürlich kann man alles so hinbiegen, dass es irgendwie funktioniert, aber das wird niemals ein klar strukturiertes, wartbares oder testbares Programm. Kreuzimporte sind immer ein Zeichen dafür, dass man sich bei der Aufteilung in Module nicht genug Gedanken gemacht, bzw. das Problem noch nicht völlig verstanden hat.
Das in meinem vorigen Post ist aber gar kein Kreuzimport
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 10:05
von Sirius3
@Alfons Mittelmeyer: das wird wieder die selbe Diskussion, wie mit globalen Zuständen, die nicht nur dadurch enstehen, dass irgendwer »global« benutzt. Kreuzimporte entstehen nicht nur, dass jemand »import« benutzt, sondern auch, wenn ich von einem anderen Modul aus Objekte als globale Variable in ein anderes Modul injiziere. Bei einem »import« ist noch relativ klar, was passiert, bei dem was Du da veranstaltest hat niemand eine Chance, nachzuvollziehen, woher denn das Edge in AbqDraw herkommt. Das ist Verschleierung und hat nichts mit programmieren zu tun.
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 10:38
von Alfons Mittelmeyer
@Sirius3: das mit der globalen Variablen, vergessen wir besser. Aber Kreuzimporte lassen sich oft nicht vermeiden, wenn man Module aufteilen will.
Ich habe etwa erweiterte tkinter Widgets, die leite ich nicht nur von tkinter ab sondern auch von einer Basisklasse GuiElement. In dieser Basisklasse gibt es auch Methoden, die abfragen, zu welcher Klasse das Widget gehört. Wenn das alles in einem Modul ist, braucht man keinen Kreuzimport. Dann kamen aber die erweiterten ttk Widgets hinzu und die wollte ich in einem anderen Modul haben. Die diese auch mit von GuiElement abgeleitet werden, muß dieses Modul mein Hauptmodul DynTkInter importieren. Da aber GuiElements auch die Klassen der widgets abfragt, muss DynTkInter auch das Ttk Modul importieren. Da die Klassen im Ttk Modul mit von GuiElements abgeleitet werden, muss GuiElements bereits bekannt sein, das heißt dass DynTkInter zuerst importiert sein muss. Aber in DynTkInter muss ich mein Ttk importieren. Aber da ich von nichts im Ttk Modul ableite, gibt es eine Lösung, nämlich dass ich am Schluss des DynTkInter Moduls erst das Ttk Modul importiere. Damit ist das kreuzweise auch in ein Hintereinander aufgelöst und verursacht keine Probleme mit nicht gefundenen Namen. Kreuzweise gegenseitig in zwei Modulen voneinander ableiten dagegen geht nicht.
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 10:44
von Alfons Mittelmeyer
Im vorliegen Fall braucht man aber keinen kreuzweisen import. Das was bei FEMesh in main steht gehört in ein Script, Das Script importiert AbiDraw und AbiDraw importiert FEMesh
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 11:02
von Alfons Mittelmeyer
Sirius3 hat geschrieben:@Alfons Mittelmeyer: das wird wieder die selbe Diskussion, wie mit globalen Zuständen, die nicht nur dadurch enstehen, dass irgendwer »global« benutzt.
Du fängst immer wieder mit den globalen Zuständen an. Man kann einen Kreuzimport so vermeiden, indem man die Module nicht zerteilt und schreibt das, was in einem anderen Modul sein sollte in eine Klasse:
Dieses ttk würdest Du jetzt als globalen Zustand ansehen. Denn bei Dir sind ja Objekte globale Zustände.
Aber das ist gleichbedeutend mit:
import Ttk as ttk
Das heißt dann, dass Imports auch globale Zustände sind und man daher Imports vermeiden sollte, oder?
Aber jetzt habe ich eine einfache Lösung
Verfasst: Samstag 12. August 2017, 11:51
von Alfons Mittelmeyer
Jede Klasse bekommt eine class_id und die kann man dann abfragen, ohne etwas zu importieren.
Wenn man das aber auch für alle Klassen aus allen importierten Modulen durchziehen will, wird es etwas aufwendig.
Code: Alles auswählen
import AbqDraw
class Edge(object):
def __init__(self):
self.parent = None
self.label = None
self.nodes = None
self.class_id = 'FEMesh.Edge'
def create_edge(self):
pass
#########################
if __name__ == '__main__':
print 'within FEMesh.py'
edge = Edge()
draw = AbqDraw.drawing()
draw.draw_edge(edge)
Wenn man aber auch Vererbung dabei braucht kann man class id Klassen machen, wobei dann class id Klassen andere class id Klassen als Basisklassen haben können.
Diese class id Klassen nebst class id Objekten hat man in einem Modul, das man überall importieren kann ohne kreuzweise. Das habe ich auch so gemacht mit Namen für widgets. Ein Name kann ein String sein oder ein Objekt einer Namensklasse.
Das löst natürlich nicht den Fall ganz am Anfang, nämlich dass man Edge zweimal definiert im Mainscript und im Modul.
Aber ich könnte dann den kreuzweisen Import vermeiden.
Jetzt habe ich für mich noch eine viel einfachere Lösung gefunden: ich brauche ja nicht abzufragen, ob eine Widget eine Instanz von einer meiner ttk Klassen ist, sondern es geht genauso ob es eine Instanz der original ttk Klassen ist.
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 17:53
von Sirius3
@Alfons Mittelmeyer: welches Problem soll denn jetzt diese »class_id« lösen?
Alfons Mittelmeyer hat geschrieben:Jetzt habe ich für mich noch eine viel einfachere Lösung gefunden: ich brauche ja nicht abzufragen, ob eine Widget eine Instanz von einer meiner ttk Klassen ist, sondern es geht genauso ob es eine Instanz der original ttk Klassen ist.
Es geht noch einfacher: gar nicht abfragen, ob ein Objekt Instanz einer bestimmten Klasse ist. Das ist nämlich so gut wie nie nötig und deutet wenn dann auf einen Designfehler hin.
Re: isinstance oder wie vergleicht man typen
Verfasst: Samstag 12. August 2017, 23:53
von Alfons Mittelmeyer
Sirius3 hat geschrieben:@Alfons Mittelmeyer: welches Problem soll denn jetzt diese »class_id« lösen?
Es geht noch einfacher: gar nicht abfragen, ob ein Objekt Instanz einer bestimmten Klasse ist. Das ist nämlich so gut wie nie nötig und deutet wenn dann auf einen Designfehler hin.
Natürlich ist das nötig. In einem Menü biete ich nicht an, dass man da Labels, Buttons, Frames und dergleichen anlegen kann. In einem Notebook oder PanedWindow biete ich kein grid, place oder pack an. Oder sollte ich das?
Re: isinstance oder wie vergleicht man typen
Verfasst: Freitag 18. August 2017, 19:00
von calo
@Alle
vielen Dank für die vielen Beiträge und guten Vorschläge.
Eines vorweg: FEMEsh.py ist selbst nur ein Unter-Modul (und kein Mainskript), dass von einem Kernel-Skript geladen wird. Daher habe ich nun zum testen eine FEMesh_test_suite.py geschrieben. Und so funktioniert es, ...und das, ganz ohne Kreuzimporte

:
Code: Alles auswählen
# FEMesh_test_suite.py
from FEMesh import *
from AbqDraw import *
edge = Edge()
draw = drawing()
draw.draw_edge(edge)
Code: Alles auswählen
# FEMesh.py
class Edge(object):
def __init__(self):
self.parent = 0
self.label = 0
self.referenced_elements = []
self.nodes = 0
def create_edge(self):
pass
def del_edge(self):
pass
class EdgeArray(list):
def __init__(self, parent, name=None, edges=[]):
list.__init__(self, edges)
self.parent = parent
self.array_name = name
def add_edge(self, node_pair, eid):
pass
def del_edges(self, edges):
pass
#######################################
if __name__ == '__main__':
print 'within FEMesh.py'
Code: Alles auswählen
# AbqDraw.py
import FEMesh
class drawing(object):
def __init__(self):
self.vertices = []
self.lines = []
def draw_edge(self, edges):
if isinstance(edges, FEMesh.Edge):
print type(edges)
print FEMesh.Edge
elif isinstance(edges, FEMesh.EdgeArray):
print type(edges)
print FEMesh.Edge
#######################################
if __name__ == '__main__':
print 'within AbqDraw.py'
Nochmals rechtherzlichen Dank an alle.