Seite 1 von 1

Wert eines Dictionaries hängt von anderem Dictionary-Wert ab

Verfasst: Mittwoch 25. März 2009, 10:35
von BastiL
Hallo zusammen,

ich bräuchte etwa so etwas:

Code: Alles auswählen

testdict={"wert1" : 5, "wert2" : 2*testdict["wert1"],}
Der Wert zum Schlüssel "wert2" hängt also dynamisch vom Wert zu Schlüssel "wert1" ab. Wie lässt sich so etwas realisieren?

Danke.

Verfasst: Mittwoch 25. März 2009, 11:07
von audax
indem du die settattr Methoden überschreibst und dir solche Hooks einbaust.

€dit sagt, da gibts nen Modul für, aber im Prinzip ist da ne Speziallösung vermutlich besser.
Wenn du die Dinge tatsächlich als "3*foo" eingeben willst, muss eben "x*foo" nen Proxy erstellen.

Verfasst: Mittwoch 25. März 2009, 11:31
von audax

Code: Alles auswählen

from functools import partial 
import operator as op

class ProxyFactory(object):

    def __init__(self, val):
        self.val = val

    def create_proxy(self, func):
        return Proxy(self, func)

    def _operation_proxy(self, func, val):
        return self.create_proxy(partial(func, val))

    def __mul__(self, other):
        return self._operation_proxy(op.mul, other)

    def __add__(self, other):
        return self._operation_proxy(op.add, other)

class Proxy(object):

    def __init__(self, parent, mod):
        self._parent = parent
        self._mod = mod

    def __getattr__(self, name):
        if not name in ("_parent", "_mod"):
            return self._mod(getattr(self._parent, name))
        else:
            return object.__getattr__(self, name)



master = ProxyFactory(5)
mul = master * 2
add = master + 1
assert mul.val == 10
assert add.val == 6
ich war mal so frei.

Verfasst: Mittwoch 25. März 2009, 11:42
von BastiL
Danke audax,

allerdings bin ich noch nicht so lange dabei als das dich das genau verstehe. Das ganze klingt ziemlich kompliziert..... Was muss ich den jetzt mit der von dir geposteten Lösung tun?

Ich bin gerade am grübeln ob das sich das nicht auch einfacher verwalten lässt, d.h ob ich eine andere Datenstruktur verwenden könnte....

Grüße

Verfasst: Mittwoch 25. März 2009, 11:55
von audax
Wo genau im Code hast du denn Probleme?
Probier einfach mal mit Teilstücken des Codes im Interpreter rum und schau in die Doku des operator und des functools Moduls. Sind alles keine schweren Dinge.
Die die object.__getattr__ Sache muss ich da machen, da ein self.foo schon wieder die eigene __getattr__ Methode aufruft und ich so eine Endlosschleife baue.

Aber na andere Datenstruktur wäre auch gut :D

Verfasst: Mittwoch 25. März 2009, 12:11
von BastiL
audax hat geschrieben:Aber na andere Datenstruktur wäre auch gut :D
Ok was ich machen möchte ist ein Interface für ein Programm schreiben, das dem Code Variablen übergibt. Die Variablen sichere ich in dictionaries, dabei ist der Variablenname der Schlüssel und der Wert der Variable der Wert. Was mich da schon stört, ist dass ich dictionaries nicht anordnen kann, außerdem würde ich gerne eine Erklärung noch irgendwie für jede Variable mitspeichern. Der User soll alle Variablen ändern können. Manche Variablen hängen von anderen Variablen ab - daher der Kunstgriff... Am Ende wird der Inhalt aller dictionaries in ein File geschrieben, dass dann die Schnittstelle darstellt.
Wie könnte denn die Datenstruktur sonst aussehen? Eventuell könnte man das über geschachtelte Listen realisieren?

Verfasst: Mittwoch 25. März 2009, 12:20
von jens
Bau einfach eine Klasse dafür. So in der Art:

Code: Alles auswählen

class Variable(object):
    def __ini__(self, name, wert, beschreibung):
        self.name = name
        self.wert = wert
        self.beschreibung = beschreibung
Hört sich aber so an, als wenn du ein dickes Fass aufmachen willst ;)

Verfasst: Mittwoch 25. März 2009, 13:11
von BastiL
Hmm, ich muss dann aber für jede neue Variable eine neue Instanz der Klasse erzeugen. Jetzt brauche ich Methoden, um zu prüfen, ob eine Varible definiert ist und ggf. den Wert zu ändern. Deshalb bin ich ja auf dictionaries gekommen - die bringen diese Methoden von Haus aus mit.
jens hat geschrieben:Bau einfach eine Klasse dafür. So in der Art:

Code: Alles auswählen

class Variable(object):
    def __ini__(self, name, wert, beschreibung):
        self.name = name
        self.wert = wert
        self.beschreibung = beschreibung
Hört sich aber so an, als wenn du ein dickes Fass aufmachen willst ;)

Verfasst: Mittwoch 25. März 2009, 13:24
von Leonidas
audax hat geschrieben:€dit sagt, da gibts nen Modul für, aber im Prinzip ist da ne Speziallösung vermutlich besser.
Ja, Trellis bzw. die ganzen CLOS Cells-Ports für Python.

Verfasst: Mittwoch 25. März 2009, 14:01
von str1442
Spricht irgendwas hiergegen?

Code: Alles auswählen

In [4]: a = {"wert1": 5, "wert2": lambda: a["wert1"] * 2}

In [5]: print a["wert2"]()
10
Du musst deine dynamischen Werte dann nur markieren, so dass du die Funktion aufrufen kannst.

Verfasst: Mittwoch 25. März 2009, 14:08
von BastiL
str1442 hat geschrieben: Du musst deine dynamischen Werte dann nur markieren, so dass du die Funktion aufrufen kannst.
Sieht eigentlich gut aus. wie meinst du das mit dem markieren?

Verfasst: Mittwoch 25. März 2009, 14:28
von str1442
Naja, du hast dann eben Funktionen statt direkter Werte, die du erst aufrufen musst. Also musst du, wenn du einen Wert abrufst, entweder ausserhalb explizit überprüfen ob du ein Funktionsobjekt zurückbekommst oder einen Wert, oder du definierst einen Boolean Status, der dir anzeigt, ob das jetzt ein "statischer" oder ein dynamischer Wert ist. Zum Beispiel könnte jeder Wert des Dict ein Tupel sein, dessen erstes Argument wie gehabt der jeweilige Wert ist und als zweiten Wert True oder False. Dokumentieren tust du das dann als "is_dynamic" oder sowas. Dann reicht ein

Code: Alles auswählen

current_dict = dict((key, (normal_dict[0][key]() if normal_dict[key][1] else normal_dict[key][0])) for key in normal_dict)
Wobei normal_dict die Funktion beinhaltet und current_dict eben alle statischen Werte + die evaluierten dynamischen Werte.

Verfasst: Mittwoch 25. März 2009, 15:30
von BastiL
Ok so langsam verstehe ich deine Idee, str1442.
Ich habe mir alternativ noch überlegt, das mit skalaren Hilfsvariablen zu lösen.

Code: Alles auswählen

testdict={"wert1" : 5,}
tmp=2*testdict["wert1"]
testdict.update({"wert2" : tmp,})
print testdict
{'wert2': 10, 'wert1': 5}
testdict["wert1"]=7
print testdict
{'wert2': 10, 'wert1': 7}
Der Initialzustand ist so stimmig. Allerdings wird die Variable "tmp" nach einer Änderung von "wert1" natürlich nicht dynamisch aktualisiert - gibt es dafür Möglichkeiten?

Verfasst: Sonntag 29. März 2009, 00:19
von kryz
vielleicht habe das problem nicht verstanden, aber würde folgendes nicht auch gehen?

Code: Alles auswählen

class MyDict(dict):
    def __setitem__(self, key, value):
        if key == 'wert1':
            dict.__setitem__(self, 'wert2', 2*value)
            dict.__setitem__(self, key, value)
        else:
            dict.__setitem__(self, key, value)

d = MyDict()
d['wert1'] = 2
print d

Verfasst: Sonntag 29. März 2009, 01:13
von str1442
Dann müsste man allerdings die Funktionen, die man braucht, gesondert abspeichern und sich eine Datenstruktur ausdenken, die alle Statischen Namen, von denen der neue Wert abhängt, in einer One to Many Relation abbilden, etwa einem Neuen dict mit <neuer_wert> => <tupel von alten werten>>. Das müsste dann in einer bestimmten Reihenfolge als Parameter an die Funktionen gegeben werden. Zumindest, wenn man das ganze generisch implementieren will. Schließlich soll das ja ein Dictionary sein, und nicht eine DoWhatEverIWantionary. Erledingt man das gleiche gleich mit lambda zuweisungen, braucht man nur sich das jeweils aktuelle Dict generieren lassen, indem man die Funktionen auswertet, die auf das Dict selbst mittels Closure Zugriff haben.