2009-06-28 12 views
1

ersten Beitrag, so spielen Sie nett!Python: Verknüpfen/Binden von Variablen zusammen in einem Wörterbuch

Ich habe eine ziemlich grundlegende Frage über Python-Wörterbücher. Ich möchte einige dict Wert haben, die Updates, wenn eine andere Variable geändert wird (oder zumindest neu berechnet, wenn es nächste genannt wird) - zB:

mass = 1.0 
volume = 0.5 
mydict = {'mass':mass,'volume':volume} 
mydict['density'] = mydict['mass']/mydict['volume'] 

So in diesem Fall myDict [ ‚Dichte‘] liefert nur 2,0 . Wenn ich mydict ['mass'] = 2.0 ändere, wird die Dichte nicht aktualisiert. Gut - ich kann verstehen, warum - die Dichte wird durch die Werte definiert, wenn sie an die Deklaration übergeben wurden. Also dachte ich, vielleicht könnte ich dies mit einem Lambda-Ausdruck nähern, zB (Entschuldigung für den schrecklichen Code!):

mydict['density_calc'] = lambda x,y: x/y 
mydict['density'] = mydict['density_calc'](mydict['mass'],mydict['volume']) 

Aber noch einmal, das gibt nur die ursprüngliche Dichte, trotz myDict Wechsel [ ‚Masse‘]. Als letzten Versuch habe ich folgendes versucht:

def density(mass,volume): return mass/volume 
mydict['density_calc'] = lambda x,y: density(x,y) 
mydict['density'] = mydict['density_calc'](mydict['mass'],mydict['volume']) 

Nochmal keine Würfel. Das scheint ein wirklich einfaches Problem zu sein, also entschuldige mich im Voraus, aber wenn mir jemand helfen könnte, wäre ich sehr dankbar!

Cheers,

Dave

Antwort

-2

Hier ist eine schnelle Hack, wie dict Unterklasse Ihre Spezifikationen zu erfüllen, aber wahrscheinlich nicht Python-Spezifikationen für ein Wörterbuch zu erfüllen:

class MyDict(dict): 
    def __getitem__(self, key): 
     if key == 'density': 
      return self['mass']/self['volume'] 
     else: 
      return dict.__getitem__(self,key) 
    def keys(self): 
     return ['density'] + dict.keys(self) 

x = MyDict() 
x['mass'] = 1.0 
x['volume'] = 0.5 

print x 

print x.keys() 

print x['density'] 

x['mass'] = 2.0 

print x['density'] 

die

{'volume': 0.5, 'mass': 1.0} 
['density', 'volume', 'mass'] 
2.0 
4.0 

druckt Aber das ist nicht unter anderem dict.iterkeys().

+2

Dies kann am nächsten an der Beantwortung der OP, aber es ist schrecklich. – FogleBird

+0

Vielen Dank für die hilfreichen Antworten. Ich hätte vielleicht deutlicher über meine Anforderungen sprechen sollen. Ich muss das Wörterbuch "herumtragen" - es wird durch viel Code geleitet und dupliziert usw. - viele der Variablen sind rechenintensiv zu berechnen. Ich hatte gehofft, keine neue Klasse zu erstellen (ich arbeite mit parallelem Python, das, wie ich finde, manchmal ein PITA für den Umgang mit Klassen sein kann), aber ich denke, ich werde diese Lösung verwenden. Prost! – Dave

+2

@Dave, sollten Sie Ihre Voreingenommenheit gegen Klassen überdenken.Rechnerisch teuer ist der Grund, warum wir Klassen verwenden. Es wird erwartet, dass eine Klasse Code hat, der unnötige Berechnungen vermeidet. Die Attribute einer Klasse sind bereits ein Wörterbuch. Ein solches Wörterbuch zu überladen, verletzt die Erwartungen anderer, indem es einen "speziellen" Schlüssel versteckt, der sich von allen anderen unterscheidet. –

3

Kurze Antwort ist, können Sie nicht.

Der zugewiesene Ausdruck wird strictly ausgewertet, wenn er auftritt, so dass Änderungen an den Begriffen später keine Rolle spielen.

Sie diese mit einer benutzerdefinierten Klasse dict lösen können, dass die getitem und SetItem Methoden überschreibt und tut etwas Besonderes (d berechnet den Wert) für einige der Tasten (sagen Dichte und eine endliche Anzahl von anderen).

class MyDict(dict): 
    def __getitem__(self, key): 
      if key == "density": 
        return self["mass"]/self["volume"] 
      return dict.__getitem__(self, key) 

d = MyDict() 
d["mass"] = 2.0 
d["volume"] = 4.0 
d["density"] # 0.5 

Werfen Sie einen Blick auf this.

9

Scheint wie ein Missbrauch einer Wörterbuchstruktur. Warum nicht eine einfache Klasse erstellen?

class Entity(object): 
    def __init__(self, mass, volume): 
     self.mass = mass 
     self.volume = volume 
    def _density(self): 
     return self.mass/self.volume 
    density = property(_density) 
4

würde eine Klasse tut dies besser:

class Thing: 
    def __init__(self, mass, volume): 
     self._mass = mass 
     self._volume = volume 
     self._update_density() 

    def _update_density(self): 
     self._density = self._mass/self._volume 

    def get_density(self): 
     return self._density 

    density = property(get_density) 

    # You're unlikely to need these, but to demonstrate the point: 
    def set_mass(self, mass): 
     self._mass = mass 
     self._update_density() 

    def set_volume(self, volume): 
     self._volume = volume 
     self._update_density() 

brick = Thing(mass=2, volume=0.8) 
print brick.density 
# Prints 2.5 

brick.set_mass(4) 
print brick.density 
# Prints 5.0 

ich Dich beim Wort nehme, dass Sie die Dichte aktualisiert werden sollen, wenn Sie die anderen Werte festgelegt - ein einfacher Weg, einfach sein würde, zu berechnen on the fly, wenn danach gefragt:

def get_density(self): 
     return self._mass/self._volume 

Dann würden Sie _update_density() überhaupt nicht brauchen.

+0

Seltsam, dass Sie über Eigenschaften kennen, aber die Dichte der Aktualisierung aller Mühe durchlaufen, wenn sich etwas ändert. Frühzeitige Optimierung? Zu viel Code. – FogleBird

+0

Oh, gerade habe ich deine Notiz unten gesehen. Warum tust du das nicht an erster Stelle? – FogleBird

+0

Ich beantwortete die Frage wie gefragt und schlug dann einen einfacheren Weg vor. Vielleicht hat Dave einen guten Grund dafür, dass der Wert aktualisiert werden soll, wenn sich etwas ändert - wie sein echtes Problem einen Wert hat, der teuer zu berechnen ist oder so. – RichieHindle

6

Am besten erstellen Sie in diesem Fall eine Klasse und verwenden eine dynamische Eigenschaft. z.B .:

 

class Body(object): 
    def __init__(self): 
     self.mass=1.0 
     self.volume=0.5 

    @property 
    def density(self): 
     return self.mass/self.volume 
 

Dies gibt Ihnen Masse, Volumen und Dichte-Eigenschaften, wo Dichte auf den beiden anderen Werten basiert berechnet. z.B.

 

b=Body() 
b.mass=1 
b.volume=0.5 
print b.density # should be 2 

b.mass=2.0 
print b.density # should be 4 
 

Allerdings, wenn Sie mit einem Wörterbuch vermählt werden Sie es wahrscheinlich verlängern sollte und überschreiben die __getitem__ und __setitem__ „Magie“ Methoden und erkennen, wenn Masse oder auch geändert hat, wenn Dichte zugegriffen wird und eine Neuberechnung nach Bedarf.

3

Das Problem ist, dass Wörterbücher nicht das richtige Werkzeug für Ihr Problem sind. Ihre Frage ist wie "wie kann ich einen Nagel mit einem Schraubenzieher einschlagen" ;-)

Wörterbücher sollen Schlüssel zu Werten zuordnen und interessieren sich nicht für andere Werte im Wörterbuch. Was Sie wollen, eine Klasse

class PhysicalObject: 
    def __init__(self, mass, volume): 
     self.mass = float(mass) 
     self.volume = float(volume) 
    def setMass(self, mass): 
     self.mass = float(mass) 
    def setVolume(self, volume): 
     self.volume = float(volume) 
    def getDensity(self): 
     return self.mass/float(self.volume) 

v = PhysicalObject(1.0, 2.0) 
print v.getDensity() # prints 0.5 
v.setMass(2.0) 
v.setVolume(1.0) 
print v.getDensity() # prints 2.0 

Dieses Beispiel zeigt die Dichte jedes Mal, wenn Sie es erhalten möchten neu berechnet ist, kaufen Sie es auch in der setMass und setVolume Funktionen berechnen kann.

1

Dies ist so einfach:

>>> mydict = {'mass':100, 'volume': 2, 'density': lambda: mydict['mass']/mydict['volume']} 
>>> mydict['density']() 
50 
>>> mydict['mass']=200 
>>> mydict['density']() 
100 
>>> mydict['volume'] = 4 
>>> mydict['density']() 
50 

Meine Lambda Referenzen myDict und später ruft auf die neuesten Daten halten in myDict, mich so sparsam die Mühe Passieren der Masse und Volumen an die Funktion jedes Mal, wenn ich will nennen sie es, wie in Ihrer Lösung:

def density(mass,volume): return mass/volume 
mydict['density_calc'] = lambda x,y: density(x,y) 
mydict['density'] = mydict['density_calc'](mydict['mass'],mydict['volume']) 

jedoch myDict [ 'Dichte'] ist eine Funktion, nicht der Wert selbst.

+0

Hmm - Ich denke, das war nahe an dem, was ich anstrebte, aber ich möchte die Funktion nicht ausführen müssen. Ein großer Teil meines Codes beruht auf den Variablen in mydict, und wenn ich neue Sachen schreibe, ist es unvermeidlich, dass ich vergesse, dass einige Schlüssel ausgeführt werden müssen, einige können nur referenziert werden. Danke für die Lösung! – Dave

0

Ein selbstreferenzielles Wörterbuch würde fast Ihren zweiten Versuch (vor 7 Jahren) entsprechen und würde gut mit jedem anderen Code, der dieses Wörterbuch verwendet, spielen. Mit anderen Worten, es wird immer noch wie eine Ente aussehen und sich verhalten.

class MyDict(dict): 
     def __getitem__(self,key): 
      value=dict.__getitem__(self,key)   
      if callable(value): 
       value=value(self) 
      return value 

mydict=MyDict({'mass':1.0,'volume':0.5}) 
mydict['density'] = lambda mydict: mydict['mass']/mydict['volume'] 

print(mydict['density']) 

2,0

mydict['mass']=2.0 
print(mydict['density']) 

4,0

Verwandte Themen