Dictionary - Bäume

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
SaschaN
User
Beiträge: 5
Registriert: Donnerstag 16. August 2018, 11:09

Hallo Forum,
ich habe ein Problem in meinem Programm und finde es nicht, bin ein Anfänger :| .
Das Programm soll Namensbereiche (Scopes) simulieren.
mit :
c <namespace> <parent> - wird eine Bereich (Funktion) im Parent erzeugt, wobei "global" der unterste Bereich ist.
a <namespace> <variable> - weist man eine Variabel dem Bereich zu.
g <namespace> <variable> - liefert den Namen des Bereichs, in dem <variable> zugewiesen wurde, also <namespace>, oder wenn die Variabel im direkten Parent vorhanden ist und nicht im <namespace> den Namen des Parent, oder Nono falls nicht vorhanden.

Dann gibt es paar Hilfsfunktionen:
p - Gibt unseren Baum(root) aus.
gc <namespace> - gibt die Kinderbereiche von <namespace> aus.

Ab der dritten Ebene funktioniert das Programm leider nicht richtig.
z.B. wenn ich
c foo global
c bar global
c fip foo
c fap foo
c bip bar
c bap bar
a bar b
g bip b
eingebe, wird None ausgegeben. Wenn ich gc bar eingebe wird auch None ausgegeben, obwohl wenn ich p eingebe, sind die Bereiche im Baum vorhanden.

[/code]
Ich finde den Fehler aber nicht, hoffe auf eure Hilfe.

Code: Alles auswählen

root = {'global': {'names' : {}, 'vars' : []}}

def create(namespace, parent, adress = root):
    for name in adress.keys():
        if name == parent:
            adress[name]['names'][namespace] = {'names' : {}, 'vars' : []}
            return
        else:
            create(namespace, parent, adress[name]['names'])

def add(namespace, var, adress = root):
    for name in adress.keys():
        if name == namespace:
            adress[name]['vars'].append(var)
        else:
            add(namespace, var, adress[name]['names'])

def get(namespace, var, lastvar = [], adress = root):
    for name in adress.keys():
        if name == namespace and var in lastvar or var in adress[name]['vars']:
            return name
        else:
            return get(namespace, var, adress[name]['vars'], adress[name]['names'])

def get_childreen(namespace, adress = root):
    for name in adress:
        if name == namespace:
             return set(adress[name]['names'].keys())
        else:
            return get_childreen(namespace, adress[name]['names'])

cmd = input()
while cmd != "":
    cmd = cmd.split()
    cmd.reverse()
    a = cmd.pop()
    if a not in ["p", "gc", "c", "a", "g"]:
        print("wrong argument")
        cmd = input()
        continue
    if a == "p":
        print(root)
        cmd = input()
        continue
    b = cmd.pop()
    if a == "gc":
       print(get_childreen(b)) 
       cmd = input()
       continue
    c = cmd.pop()
    if a  == "c":
        create(b, c)
    elif a == "a":
        add(b, c)
    elif a == "g":
        print(get(b,c))
    cmd = input()
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also die Menge an "cmd = input()" ist verstoerend. Einmal am Anfang deiner Schleife sollte das doch reichen.

Und dann schau dir mal genau an, wie dein root-Namensraum aussieht, und wie ein darunter liegender Namensraum aussieht. Da gibt es einen sehr entscheidenden Unterschied, der in meinen Augen auch einen schlechten Entwurf darstellt, und den Code verwirrend macht.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@SaschaN: Ich bin ein bisschen verwirrt was die Argumente bei den Benutzereingaben bedeuten sollen. Es muss da ja möglich sein Pfade in den Baum für Namensraumargumente angeben zu können. Der Witz bei so einem Baum ist ja gerade das man den gleichen Namen in verschiedenen Pfaden definieren kann. Also Beispielsweise den Namensraum 'parrot' im Namensraum 'spam' *und* im Namensraum 'holy_handgranade'. Sonst brauchst Du keinen Baum.

Die Definition von `root` und die Hauptschleife sollten in einer Funktion verschwinden. Und über die Hauptschleife mag ich gar nicht nachdenken solange da mehr als ein `input()` steht und ``continue`` überhaupt vorkommt. Mach da eine Endlossschleife draus (``while True:``) mit *einem* `input()` am Anfang, und keinem einzigen ``continue``. Wenn der Benutzer nichts eingibt, kann man die Schleife mit ``break`` verlassen. Das ist wesentlich übersichtlicher als der jetzige Zustand.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@SaschaN: der Trick bei Wörterbüchern ist es ja gerade, dass man nicht linear über alle Schlüssel suchen muß. Bei `create`, `add`, `get` und `get_childreen`sieht das dazu noch falsch aus, weil für jeden Schlüssel der nicht passend ist, immer der `else`-Block ausgeführt wird.
SaschaN
User
Beiträge: 5
Registriert: Donnerstag 16. August 2018, 11:09

@__deets__ und @__blackjack__ ja danke das mit input() ist mir gar nicht so aufgefallen.
Der Witz bei so einem Baum ist ja gerade das man den gleichen Namen in verschiedenen Pfaden definieren kann.
Ja stimmt, daran habe ich auch nicht gedacht. Wie gesagt, Anfänger.

@Sirius3
der Trick bei Wörterbüchern ist es ja gerade, dass man nicht linear über alle Schlüssel suchen muß.
Danke, an diesen Trick habe ich nicht gedacht, werde es aber berücksichtigen.

Danke!!!
SaschaN
User
Beiträge: 5
Registriert: Donnerstag 16. August 2018, 11:09

Also es hat bestens funktioniert.
Hier nochmal der Endcode.

Code: Alles auswählen

root = {'global': {'vars': []}}

def create(namespace, parent):
    if namespace is not 'global':
        root[namespace] = {'parent':parent, 'vars':[]}

def add(namespace, var):
    root[namespace]['vars'].append(var)

def get(namespace, var, exception = 'global'):
    if var in root[namespace]['vars']:
        return namespace
    elif namespace == exception:
        return None
    else:
        return get(root[namespace]['parent'], var)

number = int(input())   # wieviele Befehle sollen durchgearbeitet werden?
for n in range(number):
    cmd = input().split()
    befehl, bereich, argument = cmd
    if befehl  == "create":
        create(bereich, argument)
    elif befehl == "add":
        add(bereich, argument)
    elif befehl == "get":
        print(get(bereich, argument))
Nochmal Danke!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass man die Anzahl an Befehlen vorher eingeben muß, ist komisch, da solltest Du wieder eine while-Schleife benutzen. Du kannst jetzt nur noch Befehle mit genau 2 Argumenten ausführen, die auch nicht denen der Aufgabenstellung entsprechen. Namespaces haben global eindeutige Namen, ist das so gewollt?

Statt Wörterbücher würden sich hier Klassen eignen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@SaschaN: Jetzt ist das „Bäume“ im Betreff aber hinfällig, denn im Grunde kann man hier einen beliebigen Graphen anlegen und jeder Namensraum muss einen eindeutigen Namen haben. Was im Grunde der Idee von verschachtelten Namensräumen zuwider läuft. Ich hab's jetzt nicht ausprobiert, aber es sollte auch möglich sein einen Kreis zu erstellen, so dass `get()` das Programm zum Abbruch zwingt wenn das Rekursionslimit erreicht ist. So gewollt?

Beim erzeugen eines Namensraums wird ein eventuell vorhandener mit dem gleichen Namen einfach komplett durch einen neu angelegten ersetzt. Ist das so gewollt?

Man kann die gleiche Variable mehrfach erzeugen. Da fehlt wohl ein Test oder ein `set()` statt einer Liste für die Variablen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
SaschaN
User
Beiträge: 5
Registriert: Donnerstag 16. August 2018, 11:09

@Sirius3
Dass man die Anzahl an Befehlen vorher eingeben muß, ist komisch, da solltest Du wieder eine while-Schleife benutzen. Du kannst jetzt nur noch Befehle mit genau 2 Argumenten ausführen, die auch nicht denen der Aufgabenstellung entsprechen. Namespaces haben global eindeutige Namen, ist das so gewollt?
Das ist tatsächlich die ursprüngliche Aufgabenstellung, die anderen Funktionen waren nur zur Fehlersuche da, weil ich mit Bäumen nicht durchgestiegen bin.
Statt Wörterbücher würden sich hier Klassen eignen.
So weit bin ich noch nicht.
SaschaN
User
Beiträge: 5
Registriert: Donnerstag 16. August 2018, 11:09

@__blackjack__
Ist das so gewollt?
Ja, das ist nur eine Aufgabe eines Online-Kurses, keine TrueLive-Aufgabe.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@SaschaN: Ich hätte es nicht als Frage formulieren sollen: Das ist mit Sicherheit nicht so gewollt. Das Programm hat nichts mit dem Verhalten zu tun was man bei Namensräumen/Scopes erwarten würde. Die sind verschachtelt und getrennt, das heisst man kann in verschiedenen Namensräumen die gleichen Namen für untergeordnete Namensräume haben, und es sind Bäume und keine beliebigen Graphen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten