Problem mit Rückgabe von Objekten in Rekusiven Funktionen

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
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Hyperion hat geschrieben:Und wie setzt Du dann "right" und "left" ohne API-Änderung? Wie unterscheidet man dann "right" oder "left"?
Gar nicht. Das erstellen des Baumes ist Baumspezifisch und nichts was sich verschiedene Baumtypen teilen sollten. Die Suche hingegen kann man aber generalisieren.
Und wenn Du von Node erbst und die Klasse erweiterst und modifizierst, so erbst Du ja ein Attribut wie "neighbours" eh mit.
Wie du gerade selbst schön ausgeführt hast hätte neighbours in Node nichts zu suchen, weil eine hypotetische Subklasse BinaryTreeNode damit rein gar nichts anfangen könnte (außer eine readonly-Property draus zu machen dann bricht man aber mit dem obj.neighbours.append-Interface das vorher funktionierte).
Zudem habe ich doch auf die evtl. noch fehlende Logik hingewiesen und der OP hat das dann ja auch bestätigt, dass da noch was kommt.
Völlig unerheblich. Man verändert keine internen Datenstrukturen von irgendwelchen Klassen. obj.neighbours.append(child) statt obj.add_neighbour(child) ist einfach schlechter Stil. Selbst wenn add_child selbst nichts anderes macht.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Darii hat geschrieben:
Hyperion hat geschrieben:Und wie setzt Du dann "right" und "left" ohne API-Änderung? Wie unterscheidet man dann "right" oder "left"?
Gar nicht. Das erstellen des Baumes ist Baumspezifisch und nichts was sich verschiedene Baumtypen teilen sollten. Die Suche hingegen kann man aber generalisieren.
Ja eben weil man das kann, bietet sich doch eine (read-only)-Property an! Das erstellen hat doch mit der Suche eh nichts zu tun. Und genau deswegen ist es doch für die Suche unerheblich, ob ich direkt ein neighbours-Attribut oder zwei separate Attribute right / left ändern kann. Mit einer Property, die mir die Nachbarn zurückliefert, ist die Suche doch dann genau unabhängig von der Implementierung eines Nodes.
Darii hat geschrieben:
Und wenn Du von Node erbst und die Klasse erweiterst und modifizierst, so erbst Du ja ein Attribut wie "neighbours" eh mit.
Wie du gerade selbst schön ausgeführt hast hätte neighbours in Node nichts zu suchen, weil eine hypotetische Subklasse BinaryTreeNode damit rein gar nichts anfangen könnte (außer eine readonly-Property draus zu machen dann bricht man aber mit dem obj.neighbours.append-Interface das vorher funktionierte).
Mit dem bisherigen add_neighbour geht das doch auch nicht! Wenn Du intern zwei neue Attribute einführst, müssen die doch nach außen auch zu benutzen sein.

Auf der einen Seite forderst Du Kapselungen fürs Setzen und Abfragen von Nachbarn, auf der anderen Seite stellst Du dann die Generalisierung dafür selber in Frage. Wie solls denn nun aussehen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Darii hat geschrieben:Wie du gerade selbst schön ausgeführt hast hätte neighbours in Node nichts zu suchen, weil eine hypotetische Subklasse BinaryTreeNode damit rein gar nichts anfangen könnte (außer eine readonly-Property draus zu machen dann bricht man aber mit dem obj.neighbours.append-Interface das vorher funktionierte).
Mit dem bisherigen add_neighbour geht das doch auch nicht!
Hab ich das behauptet? Du willst doch neighbours vererben lassen. Das würde ein vorhandenes Interface brechen. add_neighbours hat da selbstverständlich genauso wenig was zu suchen.
Auf der einen Seite forderst Du Kapselungen fürs Setzen und Abfragen von Nachbarn, auf der anderen Seite stellst Du dann die Generalisierung dafür selber in Frage
Lies mal aufmerksam meine Posts, ich fordere nur eine Generalisierung für das Abfragen. Für das Setzten macht das wenig Sinn, was aber nichts daran ändert, dass das direkte Manipulieren einer evtl. vorhandenen neighbours-Liste eine schlechte Idee ist. Wenn man dann nämlich irgendwann noch Logik hinzufügen will oder die Art der Datenspeicherung ändern will hat man ein Problem.

Vielleicht mal zur Illustration:

Code: Alles auswählen

class TreeNode(object):
    def __init__(self, payload):
        self.payload = payload
        
    def expand(self):
        raise NotImplementedError
        
    def __repr__(self):
        return str(self)
        
    def __str__(self):
        return "<%s %s -> %s>" % (type(self).__name__, self.payload, self.expand())

class GenericTreeNode(TreeNode):
    def __init__(self, payload, children=None):
        TreeNode.__init__(self, payload)
        self._children = children[:] if children else []
    
    def expand(self):
        return self._children
    
    def add_child(self, child):
        self._children.append(child)
    
class BinaryTreeNode(TreeNode):
    def __init__(self, payload, left=None, right=None):
        TreeNode.__init__(self, payload)
        self.left = left
        self.right = right
        
    def expand(self):
        return filter(bool, [self.left, self.right])

def search_tree(node, payload):
    for node in node.expand():
        if node.payload == payload:
            return node
        else:
            return search_tree(node, payload)

tree = GenericTreeNode(2, [GenericTreeNode(4), GenericTreeNode(7)])
tree2 = BinaryTreeNode(2, BinaryTreeNode(4), BinaryTreeNode(7))
print search_tree(tree, 4)
print search_tree(tree2, 4)
search_tree funktioniert in beiden Fällen.
Antworten