Objekte in liste speichern

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
draetsch
User
Beiträge: 2
Registriert: Mittwoch 27. September 2006, 13:56

Hallo alle zusammen,

ich bin ziemlich neu bei Python und versuche gerade einen Konverter zu schreiben.
Die Ausgangsdatei ist eine Baumhierarchie, bestehend aus einzelnen Knoten, die bestimmte Attribute haben wie 'Name', 'Parent' usw.
Die Daten sind dabei in Blöcken von mehreren Zeilen zusammengefasst. In jeder Zeile steht eine Information.

Kleines Beispiel:

Code: Alles auswählen

1 Name gruppe_a
1 Parent NULL
2 Name gruppe_b
2 Parent gruppe_a
[/code]

Ich will diese Struktur jetzt in eine XML Datei schreiben. Dabei habe ich mir gedacht, ich erzeuge eine Klasse, die eine node beschreibt.

Code: Alles auswählen

class node():
	
	parent = 'null'
	name = 'null'
	
	def setName(self, n):
		self.name = n
		
	def setParent(self, p):
		self.parent = p
		
	def getName(self):
		return self.name
		
	def getParent(self):
		return self.parent
Ich lese jetzt jede Zeile ein und immer wenn der Begriff 'Name' auftaucht, will ich eine neue Instanz des Klasse 'node' erzeugen und sie in einer Liste abspeichern.

Code: Alles auswählen

def readFile(file):
	count = 0
	a = []
	f = open(file, "r")
	for l in f:
		if ( find(l, 'Name') != -1 ):
			count = count + 1
			a.insert(count, (psNode()))
			a[count].setName(split(l)[2])
		if ( find(l, 'Parent') != -1 ):
			a[count].setParent(split(l)[2])
			
		
			
	return a
Ich habe dazu mehrere Fragen.
1. In zeile 9 rufe ich setName auf. Da bekomme ich den Fehler "list index out of range".

2. Ist diese herangehensweise überhaupt in ordnung, oder gibt es bessere Möglichkeiten?

3. Um das XML herausschreiben zu können, muß ich die Liste (hier a) irgendwie so sortieren, daß die Hierarchie wieder stimmt. Ich könnte ja auch Zeilenweise auslesen und auch so schreiben, aber das funktioniert nicht, da ich später auf eine Node stoßen werde, die wieder weiter oben eingehängt werden muß.

Vielleicht hat ja jemand eine Idee. Ich wäre für informationen sehr dankbar.

Gruß
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ich lege dir ElementTree ans Herz, um das XML zu erzeugen. Ist ab Python 2.5 auch in der Standardbibliothek dabei.

Bsp.:

Code: Alles auswählen

>>> import elementtree.ElementTree as ET
>>> person = ET.Element('Person', gender='male')
>>> name = ET.SubElement(person, 'name')
>>> name.text = 'Joe'
>>> ET.tostring(person)
'<Person gender="male"><name>Joe</name></Person>'
BlackJack

draetsch hat geschrieben:ich bin ziemlich neu bei Python und versuche gerade einen Konverter zu schreiben.
Die Ausgangsdatei ist eine Baumhierarchie, bestehend aus einzelnen Knoten, die bestimmte Attribute haben wie 'Name', 'Parent' usw.
Die Daten sind dabei in Blöcken von mehreren Zeilen zusammengefasst. In jeder Zeile steht eine Information.

Kleines Beispiel:

Code: Alles auswählen

1 Name gruppe_a
1 Parent NULL
2 Name gruppe_b
2 Parent gruppe_a
Sind die Ziffern auch im Original und kennzeichnen einen zusammengehörigen Block? Das könnte man dann nämlich ausnutzen um die Zeilen zu gruppieren.
Ich will diese Struktur jetzt in eine XML Datei schreiben. Dabei habe ich mir gedacht, ich erzeuge eine Klasse, die eine node beschreibt.

Code: Alles auswählen

class node():
	
	parent = 'null'
	name = 'null'
	
	def setName(self, n):
		self.name = n
		
	def setParent(self, p):
		self.parent = p
		
	def getName(self):
		return self.name
		
	def getParent(self):
		return self.parent
Bitte nicht so viele getter/setter. Eine `__init__()` Methode wäre nett, dort könnte man die Klassenattribute hin verschieben. Und um einen Knoten mit dem Elternteil namens 'null' von einem unterscheiden zu können, der kein Elternteil besitzt, sollte man mit `None` initialisieren. Ausserdem benutzt Du die Java-Namenskonventionen.

Code: Alles auswählen

class Node(object):
    def __init__(self, name):
        self.name = name
        self.parent = None
        self.children = list()
    
    def add_child(self, node):
        self.children.append(node)

Code: Alles auswählen

def readFile(file):
	count = 0
	a = []
	f = open(file, "r")
	for l in f:
		if ( find(l, 'Name') != -1 ):
			count = count + 1
			a.insert(count, (psNode()))
			a[count].setName(split(l)[2])
		if ( find(l, 'Parent') != -1 ):
			a[count].setParent(split(l)[2])
			
		
			
	return a
Ich habe dazu mehrere Fragen.
1. In zeile 9 rufe ich setName auf. Da bekomme ich den Fehler "list index out of range".
Da in der Zeile zweimal auf einen index zugegriffen wird, ist die Frage welcher von beiden Schuld ist.

Auf jeden Fall ist die Sache mit `count` und `insert()` überflüssig wenn Du den neuen Knoten einfach mit `append()` an die Liste anhängen würdest.
2. Ist diese herangehensweise überhaupt in ordnung, oder gibt es bessere Möglichkeiten?
Ich denke es gibt bessere. So bekommst Du ja nur eine Liste und keine Baumstruktur. Wenn man sich die Namen und den dazugehörigen Knoten in einem Dictionary ablegt, kann man in einem zweiten Schritt die Knoten wirklich zu einem Baum verknüpfen, also als `parent` das jeweilige `Node` Objekt eintragen und eine Liste mit Kindknoten an jeden Knoten hängen.

Code: Alles auswählen

def read_nodes(lines):
    nodes = dict()  # Name -> Node
    current_node = None
    # 
    # Read the nodes.
    # 
    for line in lines:
        elements = line.split()
        if elements[1] == 'Name':
            name = elements[2]
            current_node = Node(name)
            nodes[name] = current_node
        elif elements[1] == 'Parent' and elements[2] != 'NULL':
            current_node.parent = elements[2]
    # 
    # Link the nodes and find root(s).
    # 
    roots = list()
    for node in nodes.itervalues():
        if node.parent is None:
            roots.append(node)
        else:
            node.parent = nodes[node.parent]
            node.parent.add_child(node)
    
    if len(roots) != 1:
        raise ValueError('this is not a tree, found %d roots' % len(roots))
    
    return roots[0]
Die Funktion gibt jetzt den Wurzelknoten des Baums zurück oder löst eine Ausnahme aus, wenn es keine oder mehr als eine Wurzel gibt.
3. Um das XML herausschreiben zu können, muß ich die Liste (hier a) irgendwie so sortieren, daß die Hierarchie wieder stimmt. Ich könnte ja auch Zeilenweise auslesen und auch so schreiben, aber das funktioniert nicht, da ich später auf eine Node stoßen werde, die wieder weiter oben eingehängt werden muß.
Hier bin ich jetzt etwas verwirrt, wie denn die Ausgabe überhaupt aussehen soll. Ich ging bei XML davon aus, dass die Knoten wirklich verschachteltes XML ergeben sollten. Das liesse sich im einfachsten Fall mit einer rekursiven Methode auf den Knoten-Objekten machen.
draetsch
User
Beiträge: 2
Registriert: Mittwoch 27. September 2006, 13:56

Auch wenn die Antwort meinerseits sehr lange gedauert hat. Vielen Dank. Ihr habt mir sehr geholfen.
Antworten