multiple inheritance oder eine andere Lösung?

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
CM

Samstag 14. August 2004, 20:41

Hi

stehe gerade furchtbar auf dem Schlauch (obwohl Dookie ja schon ein bißchen weitergeholfen hat). Das Problem ist Folgendes: Ich importiere zunächst ein paar Module:

Code: Alles auswählen

import sys, os
import wx
# import own modules from src
import src.DNA
import src.NCBIstrip
Bei src.DNA handelt es sich um ein eigenes Modul DNA mit der Klasse DNA, die ich jetzt in ein GUI einarbeiten möchte. Wie man sieht verwendet wxPython.

Dann steige ich ins GUI ein:

Code: Alles auswählen

class FindFrame(wx.Frame): 
	def __init__(self,parent,id,title):
wx.Frame.__init__(self,parent,id,title,wx.DefaultPosition,wx.DefaultSize,style=wx.DEFAULT_FRAME_STYLE)
           # code, code, code ...
Also alles Standard hoch drei.
Später öffne ich dann einen file dialog und möchte den gelandenen string einem "DNA-Objekt" zuweisen:

Code: Alles auswählen

#innerhalb der Klasse
def GenomicOpen(self,event):
		wildcard="stripped files (*.strip)|*.strip|"\
				 "NCBI files (*.html)|*.html|"\
				 "All files (*.*)|*.*"
		file_dialog = wx.FileDialog(self,message="Open Genomic Sequence",defaultDir=os.getcwd(),defaultFile="",wildcard=wildcard,style=wx.OPEN|wx.CHANGE_DIR)
		if file_dialog.ShowModal() == wx.ID_OK:
			path = file_dialog.GetPaths()
			infile = open(path[0])
			DNAstring = infile.read()
			inputDNA = src.DNA.__init__(DNAstring)
			infile.close()
			print inputDNA
		file_dialog.Destroy()
Ursprünglich habe ich das DNA-Modul in eine Anwendung ohne GUI eingebettet. Aber das wurde zu komplex und anwenderunfreundlich. Also habe ich mich entschieden mich (zum ersten Mal) an einem GUI zu probieren.

Das Problem ist: Wie mache ich inputDNA zu einem DNA-Objekt? Wie rufe ich innerhalb von FindFrame Funktionen von DNA auf, bzw. wie wende ich sie auf DNA-Objekte an? Ich habe mich an multiple inheritance versucht, also "class FindFrame(wx.Frame,src.DNA.DNA):", aber dabei fliegt mein Program immer auf die Schna... . Auch ohne multiple inheritance (wie heißt das auf eigentlich auf Deutsch?) ist mir die Syntax nicht ganz klar.

Im Ursprungsskript läuft alles reibungslos und DNA.__init__ initialisiert, so wie es soll. Der fragliche Code sieht so aus:

Code: Alles auswählen

DNAstring = infile.read()
input_DNA = DNA(DNAstring)
input_DNA.name(fname) # ruft die Funktion name() innerhalb der DNA-Klasse auf. 
#wie ginge das hier?
Das obige Beispiel gibt folgenden Fehler, wenn die Funktion aufgerufen wird:
Traceback (most recent call last):
File "find.py", line 75, in GenomicOpen
inputDNA = DNA.__init__(DNAstring)
NameError: global name 'DNA' is not defined

Das kann ich natürlich mit src.DNA.DNA.__init__ anstell von DNA.__init__ umgehen, es löst aber das Problem mit den anderen Funktionen nicht.

Noch der Form halber: Ich verwende OS X 10.3.5 und pythonw 2.3.3.

Vielen Dank im Vorraus!
Christian

PS Die Einrückung scheitert in meinem Code hier, ist aber in meinem Skript in Ordnung.
PPS infile.read() macht auf bei großen Dateien keine Schwierigkeiten.
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Samstag 14. August 2004, 20:57

Hi CM,

Der Fehler liegt in der Erzeugung des DNA-Objekts.

Code: Alles auswählen

#innerhalb der Klasse
def GenomicOpen(self,event):
        wildcard="stripped files (*.strip)|*.strip|"\
                "NCBI files (*.html)|*.html|"\
                "All files (*.*)|*.*"
        file_dialog = wx.FileDialog(self,message="Open Genomic Sequence",
                defaultDir=os.getcwd(),
                defaultFile="",wildcard=wildcard,
                style=wx.OPEN|wx.CHANGE_DIR)
        if file_dialog.ShowModal() == wx.ID_OK:
            path = file_dialog.GetPaths()
            infile = open(path[0])
            DNAstring = infile.read()
            # hier muss ein DNA-Objekt erzeugt werden
            self.inputDNA = src.DNA(DNAstring) #??? nicht __init__ !
            infile.close()
            print self.inputDNA
        file_dialog.Destroy() 
wenn du das DNA-Objekt an self.inputDNA zuweist, kannst Du es auch später in anderen Methoden verwenden, sonst ists nach dem Beenden der Methode futsch!


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
CM

Samstag 14. August 2004, 21:26

Tut mir leid, das hatte ich schon versucht und wohl auch sagen sollen. Dieser Versuch provoziert nämlich folgende Antwort:

Traceback (most recent call last):
File "find.py", line 75, in GenomicOpen
self.inputDNA = src.DNA(DNAstring)
TypeError: 'module' object is not callable

Als eine mögliche Alternative erscheint mir (bin gerade drauf gekommen):

Code: Alles auswählen

self.inputDNA = src.DNA.DNA(DNAstring)
self.inputDNA.name = src.DNA.DNA.name(path[0])
Hierbei klappt die Initialisierung, wenn die Klasse so aufgerufen wird: "class FindFrame(wx.Frame,src.DNA.DNA):". Aber die Funktion DNA.name kann ich nicht aufrufen:

Traceback (most recent call last):
File "find.py", line 76, in GenomicOpen
self.inputDNA.name = src.DNA.DNA.name(path[0])
TypeError: unbound method name() must be called with DNA instance as first argument (got str instance instead)

Die Implementation von name() in DNA ist schlicht:

Code: Alles auswählen

def name(self, name):
    	self.name = name
und dient hier einfach nur als Test.

Vielen Dank für die Antwort. (Hoffentlich bekomme ich noch einen Tipp für das zweite Problem. Danke)

Christian
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Samstag 14. August 2004, 21:55

Code: Alles auswählen

def name(self, name):
        self.name = name 
ist keine gute Idee, damit überschreibst Du das Attribut self.name, das eine Methode ist, mit dem argument name, das irgendein Objekt ist.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
CM

Montag 16. August 2004, 20:35

Danke.

Hoffe jetzt alleine klar zu kommen. Falls nicht, werde ich mich halt noch mal melden ... :wink:

Gruß,
Christian
CM

Mittwoch 18. August 2004, 08:19

Nachtrag & off-topic Frage ... gewissermaßen zumindest.

Dookie, dank Deiner Hilfe bin ich schon ein gutes Stück weitergekommen. Du hast unlängst unter "Codesnippets" eine "Line"-Klasse vorgestellt. Diese scheint mir sehr attraktiv für folgendes Ziel: Ich würde gerne die Ausgabe der DNA-Klasse, die ursprünglich auf die Kommandozeile (also stdout) ging in ein Textfeld umlenken, das in der __init__ Funktion von FindFrame folgendermaßen generiert wird:

Code: Alles auswählen

TextField = wx.TextCtrl(p,-1,"Nothing selected, yet.\n\n",size=(500,200),style=wx.TE_MULTILINE)
Wenn nun, wie hier, das Hauptskript mit der GUI ein Modul mit einer Klasse importiert, wie kann man deren Ausgabe so umlenken, daß es in "TextField" erscheint? Geht das mit Deiner Line-Klasse? Wenn ja, wie? Deine Klasse in das DNA-Modul importieren bzw. hineinkopieren - und dann?

Wäre wirklich toll, wenn Du mir da helfen könntest - oder sonst jemand. Wenn das Programm eines schönen Tages mal laufen sollte, will ich es auch gerne teilen.

Gruß,
Christian
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Mittwoch 18. August 2004, 12:10

Hi CM,

jo meine Line-Klasse ist genau für sowas gedacht.

Am Besten lässt Du Deine Klasse die Ausgaben in eine Datei schreiben, statt einer Datei übergibst Du beim __init__ eben ein Line-Objekt. Bei diesem Line-Objekt kannst Du dann, bei Deinem Beispiel, als reciever "TextField.AppendText" (ohne Klammern!!!) als Argument übergeben oder später mit add_reciever zuweisen.

Code: Alles auswählen

TextBuffer = Line("", TextField.AppendText)

Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Gast

Mittwoch 18. August 2004, 16:21

In eine Datei umlenken? Hmm, bin gerade erst aufgestanden (Zeitverschiebung), aber weiß nicht, ob ich das so einfach probieren will:

Zunächst habe ich, faul wie ich bin, versucht stdout auf TextField umzulenken. Das funktioniert auch, aber die Ausgabe erfolgt erst, wenn der Prozess, der sie generiert, beendet ist. Im ursprünglichen Commandline-Skript trat dieses Problem natürlich nicht auf. Ich habe Funktionen innerhalb der DNA-Klasse Text-Ausgaben produzieren lassen, um anzuzeigen, daß der Prozess noch läuft und welche Richtung vom Prozess eingeschlagen wird. Da erschien mir Textausgabe am besten.

Ok, nun dauert so ein Prozess schon mal ein kleines Weilchen (in einem "kleinen" Testfall mit einem 4 Mb Datensatz eine knappe Minute) und reklamiert (bei mir mit einem Prozessor) nahezu 100% der CPU. Wenn ich jetzt in eine Datei schreiben lasse, wird dann nicht der Prozess (und die Ausgabe) erheblich verlangsamt?

Gruß,
Christian
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Mittwoch 18. August 2004, 16:30

Hi Christian,

es ist ja nicht wirklich eine Datei, sonder ein Objekt das sich wie eine Datei verhält. Du kannst Die Ausgabe dadurch forcieren, indem du einfach ein time.sleep(0.01) nach jeder Ausgabe aus dem Thread einfügst, das verlangsamt die Ausführung der Downloads kaum.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
CM

Donnerstag 19. August 2004, 23:18

Hoi Dookie,

inzwischen habe ich etwas refactoring betrieben und mein DNA-Modul aufgeräumt. Leider fehlt mir für den Rest der Aufräumarbeiten noch etwas Input.
Ähnlich wie mawe (im Codesnipplets Forum) stehe auch ich auf dem Schlauch, was die Syntax für Dein Modul anbelangt. Deshalb traue ich mich mal treu-doof folgende zwei Fragen zu stellen, von denen ich glaube, daß sie bei mir auch ein grundlegendes Verständnisproblem in Python abdecken würden:

Wenn ich nun Deine Line-Klasse in das DNA-Modul importiere und in der GUI möchte ich ein TextCtrl-Feld als Empfänger haben: Wie muß ich (syntaktisch korrekt) den receiver im DNA-Modul bezeichnen und was muß ich hierzu in die GUI-Klasse schreiben? Muß ich überhaupt etwas in das Hauptskript mit der GUI-Klasse schreiben?

Eigentlich hat das ja nichts mit GUIs zu tun, sondern eher mit der allgemeinen Frage, wie ich einen Stream von einem Modul zum anderen öffne. Ich habe mir in diesem Zusammenhang auch mal das buildin logging Modul angeschaut, bin aber auch nicht schlauer geworden. Deshalb möchte ich hier auch noch "unverfroren" fragen, ob jemand vielleicht Beispielcode (Link?) weiß, in dem das logging Modul für diesen Zweck verwendet wird? Oder gibt es noch eine weitere / einfachere Alternative?

Vielen Dank,
Christian
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Freitag 20. August 2004, 01:16

Hi CM,

also erstmal braucht das DNA-Modul weder die Line-Klasse zu kennen noch sie zu importieren, am Besten schreiben die Funktionen/Methoden des DNA-Moduls die Ausgaben an ein, als Argument übergenenes, Dateiähnliches objekt. Das kann dann die Console über sys.stdout oder eben ein Line-Objekt aus Meinem Modul sein.
Das GUI-Modul importiert dann das DNA-Modul und das Linebuffer-Modul und stellt eine Recieverfunktion zur Verfügung, hier kann oft schon direkt eine Methode eines Widgets zum darstellen von Text verwendet werden oder es wird eine Interfacefunktion als Reciever vewendet, die dann die Ausgabe vom Lineobjekt in das Widget macht. Da ein Lineobjekt mehrere Reciever gleichzeitig bedienen kann, kann auch ein Logfile geschrieben werden.
Beim wx-TextCtrl-Feld kannst du gleich die Methode "AppendText" als Reciever verwenden.

Also in der GUI-Klasse erstmal ein Line-Objekt erstellen mit "AppendText" vom TextCtrl-Feld als reciever und das Line-Objekt dann als "Datei"-Objekt, in welches die Ausgaben geschrieben werden, an das DNA-Objekt, eventuell in der __init__-Methode übergeben.

Ich mach noch ein Beispiel, das findest dann im Linebuffer-Thread bei den Codesnipplets.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
CM

Freitag 20. August 2004, 05:48

Hoi Dookie,

Super! Vielen, vielen Dank! Hat leider ein wenig gedauert, bevor ich begriffen habe, aber Dein Beispiel (im andren Forum) hilft wohl auch dem Begriffsstutzigsten auf die Sprünge. (Damit kann ich nur mich meinen, niemanden sonst :wink: )

So, für mich heißt das jetzt einige Zeilen Code ändern, aber das wird sich wohl jetzt auch lohnen ...

Besten Gruß,
Christian
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Freitag 20. August 2004, 10:04

Hi!
CM hat geschrieben: Damit kann ich nur mich meinen, niemanden sonst
Keine Angst, Du bist nicht alleine :wink:. Ich zähle mich ohne zu Zögern auch dazu.
CM hat geschrieben: Wenn das Programm eines schönen Tages mal laufen sollte, will ich es auch gerne teilen.
Darauf bin ich schon sehr gespannt. Kannst Du jetzt schon verraten was das Programm machen wird. Scheint ja irgendwie meine Studienrichtung zu streifen (Biochemie-Bioinformatik).

Gruß, mawe
Gast

Freitag 20. August 2004, 16:32

Hoi mawe
Kannst Du jetzt schon verraten was das Programm machen wird. Scheint ja irgendwie meine Studienrichtung zu streifen (Biochemie-Bioinformatik).
Occh, aaalso: Das kann erstens noch ein paar Wochen dauern (arbeite ja schließlich nebenher und habe ein Leben nebenher) und wird zweitens das Werk eines Anfängers! Und drittens sucht es u.a. in bakteriellen Genomen best. Sequenzen und die flankierenden Bereiche. Im konkreten Fall habe ich mich darüber aufgeregt, daß eine Klonierung zu planen mit der bestehenden Software tricky oder / und teuer ist. (Also habe ich erst einmal ein paar kleine commandline scripts geschrieben ...) Und jetzt sollen halt ein paar dieser Scripte ein GUI bekommen (wirklich bloß erste Gehversuche!). U.a. eben ein kleines Script, daß Sequenzen und die flankierenden Bereiche aus einem Genom rausschreibt und zurückgibt; Input ist eine Sequenz oder Ziffern, welche die Position im Genom angeben.

Lange Rede, kurzer Sinn: BioPython ist mit Sicherheit die bessere (und professionellere) Alternative. (Aber Danke für die Blumen :-) )

Gruß,
Christian

PS Was ich eigentlich mache: siehe www.amp.ucdavis.edu
Antworten