Was mache ich, wenn ich eine selbstreferentielle Wörterbuch?
Ich bin neu in Python und bin irgendwie überrascht, dass ich dies nicht kann.
dictionary = {
'a' : '123',
'b' : dictionary['a'] + '456'
}
Frage ich mich, was die Pythonic way, richtig zu tun, diese in mein Skript, weil ich das Gefühl, ich bin nicht die einzige, die versucht hat, dies zu tun.
EDIT: Genug Leute, die sich Fragen, was mache ich mit diesem, so sind hier weitere details für meine Anwendungsfälle. Können sagen, ich möchte zu halten dictionary-Objekte, um Dateisystem-Pfade. Die Pfade sind relativ zu anderen Werten in das Wörterbuch. Dies ist ein Beispiel für das, was eines meiner Wörterbücher Aussehen könnte.
dictionary = {
'user': 'sholsapp',
'home': '/home/' + dictionary['user']
}
Ist es wichtig, dass an jedem Punkt in der Zeit, die ich ändern kann dictionary['user']
alle Wörterbücher-Werte die änderung widerzuspiegeln. Auch dies ist ein Beispiel, was ich benutze es für, so hoffe ich, dass es vermittelt mein Ziel.
Aus meiner eigenen Forschung ich glaube, ich benötigen, um zu implementieren eine Klasse, dies zu tun.
- Könnte ich machen, der Ausdruck faul um dies zu beheben?
- Sie wollen den Wert von
dictionary['b']
statisch oder dynamisch? Was würdedictionary
Aussehen nachdictionary['a'] = '999'
? - Ich wollte gerade meinen Beitrag Bearbeiten, diese Frage zu beantworten. Ich will es statisch zu sein, und erkennen, dass g.d....d....c die Antwort würde durch die dynamische. :/
- Verwandte: > Verwendet der self-referencing-Listen
- Ich kann nicht verstehen, warum würden Sie wollen, dies zu tun, statt nur über lokale Variablen, die für Ihre Werte werden in relation zu anderen Werten. Aber da Sie Fragen, die Pythonic Weg, dies zu tun, es ist sicherlich Daniel DiPaolo Ansatz.
- Ich bin mit Jeffrey: Es muss einen besseren Weg, das zu tun, was auch immer es ist Sie versuchen zu erreichen. Wenn Sie mehr Einzelheiten, die wir vielleicht in der Lage sein, um Ihnen zu helfen.
- Gibt es Sprachen, in denen Sie mit einem Wert von dem, was Sie sind zu definieren, während es zu definieren? (so können Sie fahren, während Sie fahren)
- Wo ist "g".d....d....c die Antwort," dass jeder meint?
- McCutchen, ich aktualisiert die post mit einem use-case. @Nick, ich kann in F# oder Scheme. @martineau, muss Er nach dem löschen der post, weil es nicht kompilieren auf Python 2.4 oder Python 2.6 (die letztere version als die version, die er behauptete, es funktionierte auf). Seine Lösung war meine bevorzugte Lösung, aber...
- Es wurde zurückgezogen/gelöscht, weil Missverständnis.
- Beachten Sie, dass wenn Sie tatsächlich zum bauen von Pfaden wie in deinem Beispiel, sollte man es mit
os.path.join
, vor allem, wenn es irgendeine chance, dass dein code ausgeführt wird, unter Windows. - Guter Punkt. Die unterschiedlichen os-path-Trennzeichen benutzt werden konnte, indem ein Eintrag in das Wörterbuch auf den Wert von
os.sep
und darauf zu verweisen. Zum Beispiel, indem die akzeptierten Antworten unten, Sie konnte etwas tun, wie'home' : '%{sep}shome%{sep}s%{user}s',
. - Das ist immer noch unix-spezifisch. Verwenden Sie os.Pfad.expanduser ('~'), um den Benutzer-home-Verzeichnis, und leiten Sie alle Pfade von Windows nicht einen einzigen Dateisystem-root).
Du musst angemeldet sein, um einen Kommentar abzugeben.
Keine Angst vor der Erstellung von neuen Klassen -
Sie können die Vorteile von Python string-Formatierung Fähigkeiten
und einfach tun:
__getitem__()
etwas wieeval(dict.__getitem__(self, item) % self, globals())
. Natürlich für die Sicherheit würden Sie wahrscheinlich wollen, um zu beschränken, was in dem Wörterbuch argument übergeben und nicht wirklich verwenden, globals (), die hat alle gelieferten in es.;¬)
Zu unterstreichen, meinen früheren Kommentar über Sie potenziell sehr Kalkulationstabelle-wie, hier ist ein Rezept mit einer vollständigen Umsetzung dieser Idee (von einem Python-core-Entwicklern).Nächstgelegene ich kam ohne Objekt:
dictionary['home']()
wird immer dann verwendet, statt der üblichendictionary['home']
Methode—das bedeutet natürlich, es wird wahrscheinlich nicht arbeiten im code, die noch nicht (oder kann nicht) geändert, dies zu tun...Es funktioniert gut, aber wenn Sie versuchen, zu verwenden
dictionary
es wurde noch nicht definiert noch (weil es zu bewerten, dass der literal-Wörterbuch zuerst).Aber vorsichtig sein, denn dieses weist auf die Taste
'b'
der Wert wird durch den Schlüssel des'a'
bei der Zuweisung und ist nicht zu tun, die lookup-jedes mal. Wenn es das ist was du suchst, es ist möglich aber mit mehr Arbeit.dictionary.update({'b': dictionary['a'] + '456'})
und pass auf wie groß ein Wörterbuch, wie Sie wollen, aber es klingt wie g.d....d....c hat den Ansatz, den Sie wollen, und das ist wirklich selbstreferentielle und dynamische Suche und nicht nur "at-Zuordnung-Zeit" Suche.Was Sie beschreiben Ihre Bearbeitung ist wie eine INI-config-Datei funktioniert. Python hat eine eingebaute Bibliothek namens ConfigParser die arbeiten sollten für das, was du beschreibst.
Dies ist ein Interessantes problem. Wie es scheint, Greg gute Lösung. Aber das ist auch kein Spaß 😉
jsbueno als sehr elegante Lösung aber das gilt nur für strings (wie gewünscht).
Der trick, um eine 'Allgemeine' selbstreferentielle Wörterbuch ist die Verwendung eines Surrogat-Objekt. Es dauert ein wenig (Untertreibung) Zeilen code zu ziehen, aber die Nutzung ist über das, was Sie wollen:
Den code zu machen, was passiert ist, nicht annähernd so kurz ist. Es lebt in drei Klassen:
Als Nächstes kommt die konkrete Klasse. einfach genug.
Hier das Finale der Klasse
In Reaktion auf gnucoms auf die Frage, warum ich den Namen der Klassen, die die Art und Weise, die ich Tat.
Das Wort Leihmutter ist in der Regel im Zusammenhang mit Stand-in für etwas anderes, so schien es angemessen, weil das ist, was die
SurrogateDict
Klasse hat: eine Instanz ersetzt, die "selbst" - Referenzen in ein dictionary-literal. Dass gesagt wird, die (andere als nur gerade nach oben dumm manchmal) die Benennung ist wahrscheinlich eines der schwierigsten Dinge für mich zu Programmieren. Wenn Sie (oder jemand anderes) kann vorschlagen, einen besseren Namen habe, bin ich alle Ohren.Werde ich eine kurze Erklärung. Während
S
verweist auf eine Instanz von SurrogateDict undd
ist das eigentliche Wörterbuch.Einen Verweis
S[key]
löstS.__getitem__
undSurrogateDictEntry(key)
imd
.Wenn
S[key] = SurrogateDictEntry(key)
aufgebaut ist, speichert eskey
. Dies wird diekey
ind
für den Wert, dass dieser Eintrag vonSurrogateDictEntry
fungiert als Surrogat für.Nach
S[key]
zurückgegeben wird, ist es entweder trat in dend
hat oder eine operation(en) durchgeführt wird. Wenn ein Vorgang durchgeführt wird, löst die relative__op__
Methode, die einfach speichert den Wert, der die operation durchgeführt wird, und den Namen der operation und dann wieder sich selbst. Können wir nicht wirklich beheben, den Betrieb, weild
wurde noch nicht gebaut, noch nicht.Nach
d
wird gebaut, es wird anS.resolve
. Diese Methode durchläuftd
finden Sie alle Instanzen vonSurrogateDictEntry
und ersetzt Sie mit dem Ergebnis des Aufrufs derresolve
Methode auf der Instanz.Den
SurrogateDictEntry.resolve
- Methode erhält, die jetzt gebautd
als argument und verwenden Sie können den Wert derkey
dass es gespeichert bei der Konstruktion Zeit, um den Wert, dass es als Surrogat für. Wenn eine operation wurde durchgeführt, nachdem die Erstellung, dieop
Attribut wird gesetzt wurden, mit den Namen der operation, die durchgeführt wurde. Wenn die Klasse einen__op__
Methode, dann hat es einen__op__resolve__
- Methode mit der eigentlichen Logik, die normalerweise in der__op__
Methode. So, jetzt haben wir die Logik (self.op__beheben) und alle notwendigen Werte (selbst.Wert, selbst.stored_value) um endlich den realen Wert derd[key]
. So kehren wir, dass die Schritt 4 Plätze im Wörterbuch.schließlich die
SurrogateDict.resolve
Methode gibtd
alle Referenzen aufgelöst.Dass ' a eine grobe Skizze. Wenn Sie nicht mehr Fragen haben, fühlen Sie sich frei, zu Fragen.
L[foo] + 4 + 4
fehlschlagen könnte.L[3] + L[3] + 1
aber funktioniert. Ich bin mir nicht sicher über1 + L[3] + l
aber ich denke, dass das scheitern würde. Die beiden (angeblichen) Fehler korrigiert werden konnte, indem erSurrogateDictEntry
implementieren eine operation stack, anstatt nur die Speicherung einer operation/Wert-paar.Wenn Sie, genau wie ich, Wandern wie zu machen @jsbueno snippet Arbeit mit {} style Substitutionen, unten ist der Beispiel-code (was wohl nicht sehr viel effizienter, wenn):
Habe ich versucht, es mit dem einfachen Austausch der
% self
mit.format(**self)
aber es stellt sich heraus, es würde nicht funktionieren für verschachtelte Ausdrücke (wie " bin " in obiger Liste, die Verweise 'Heimat', die es in sich hat eigene Referenz zu "Benutzer"), weil die Bewertung Bestellung (** ausbau erfolgt, bevor die eigentliche format-Aufruf, und es ist nicht verzögert, wie im original, % - version).Schreiben Sie eine Klasse, die vielleicht etwas mit den Eigenschaften:
Bisschen wie eine erweiterte version von @Tony ' s Antwort, Sie bauen konnte Wörterbuch-Unterklasse, die fordert, Ihre Werte, wenn Sie callables:
Natürlich dies wäre nur dann brauchbar, wenn Sie nicht wirklich gehen, um zu speichern callables als Werte. Wenn Sie brauchen, um in der Lage zu tun, könnten Sie wickeln die lambda-Deklaration in einer Funktion fügt hinzu, dass einige Attribut der resultierende lambda, und überprüfen Sie es in
CallingDict.__getitem__
, aber an diesem Punkt es ist immer Komplex und langatmig genug, dass es könnte nur sein, einfacher zu benutzen eine Klasse für Ihre Daten in den ersten Platz.Dies ist sehr einfach in ein träge ausgewertet Sprache (haskell).
Da Python ist streng bewertet, können wir einen kleinen trick schalten Sie die Dinge faul:
Syntax klug, das ist nicht sehr nett. Das ist, weil von uns benötigen, explizit konstruieren faul Ausdrücke mit
lambda: ...
und explizit zu bewerten faul Ausdruck mit...()
. Es ist das umgekehrte problem in faul Sprachen benötigen strenge Anmerkungen, hier in Python, die wir am Ende brauchen faul Anmerkungen.Ich denke, mit etwas mehr meta-programmming und einige weitere tricks, die oben gemacht werden konnten, einfach zu bedienen.
Beachten Sie, dass dies im Grunde, wie let-rec funktioniert in einigen funktionale Sprachen.