2009-06-28 2 views
1

первое сообщение, поэтому играйте хорошо!Python: связывание/привязка переменных вместе в словаре

У меня есть довольно простой вопрос о словарях Python. Я хотел бы иметь какое-то значение Dict, что обновления, когда другая переменная изменяется (или, по меньшей мере, пересчитывается при его следующем вызове) - например:

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

Таким образом, в этом случае, mydict [ «плотность»] просто возвращает 2.0 , Если я изменю mydict ['mass'] = 2.0, плотность не будет обновляться. Хорошо. Я могу понять, почему - плотность определяется значениями, когда они были переданы в декларацию. Так что я подумал, что я мог бы подойти к этому с лямбда-выражения, например (Извиняюсь за жуткой код!):

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

Но опять же, это только возвращает первоначальную плотность, несмотря на изменение mydict [ «массы»]. В качестве последней попытки я пробовал это:

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']) 

Опять же, нет кубиков. Это кажется очень простой проблемой для решения, поэтому извиняюсь заранее, но если кто-нибудь сможет мне помочь, я буду очень благодарен!

Приветствия,

Dave

ответ

-2

Вот быстрый хак о том, как подкласс dict, чтобы удовлетворить ваши спецификации, но, вероятно, не отвечают спецификации языка Python для словаря:

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'] 

, который печатает

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

Но это не учет dict.iterkeys(), между прочим.

+2

Это может быть ближе всего к ответу на OP, но это ужасно. – FogleBird

+0

Спасибо всем за полезные ответы. Возможно, я должен был более подробно изложить свои требования. Мне нужно «переносить» словарь вокруг - он проходит через множество кода и дублируется и т. Д. - многие из переменных вычислительно дорого вычисляются. Я надеялся не создавать новый класс (я работаю с параллельным python, который я нашел, может быть PITA для обработки классов иногда), но я думаю, что я буду использовать это решение. Ура! – Dave

+2

@Dave, вы должны переосмыслить свое предвзятое отношение к классам.Вычислительно дорого - причина, по которой мы используем классы. Ожидается, что у класса будет код, который позволит избежать ненужных вычислений. Атрибуты класса уже являются словарем. Перегрузка такого словаря нарушает ожидания других людей, скрывая «специальный» ключ, отличный от всех остальных. –

3

Короткий ответ вы не можете.

Назначенное выражение оценивается strictly, когда оно встречается, поэтому любые изменения терминов в дальнейшем не имеют значения.

Вы могли бы решить эту проблему с помощью пользовательского класса Dict, который переписывает GetItem и SetItem методы и делает что-то особенное (т.е. вычисляет значение) для некоторых клавиш (скажем, плотность и конечное число других).

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 

Посмотрите на this.

9

Похоже на злоупотребление структурой словаря. Почему бы не создать простой класс?

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

класс будет делать это лучше:

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 

Я отвезу тебя на слове, что вы хотите плотность обновляется при установке других значений - проще всего было бы просто вычислить это на лету, когда напросился:

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

Тогда вам не нужно _update_density() вообще.

+0

Странно, что вы знаете о свойствах, но пройти через все трудности обновления плотности всякий раз, когда что-то меняется. Преждевременная оптимизация? Слишком много кода. – FogleBird

+0

О, только что увидела вашу записку внизу. Почему бы не сделать это в первую очередь? – FogleBird

+0

Я ответил на вопрос, как задал вопрос, а затем предложил более простой способ. Возможно, у Дэйва есть веская причина для того, чтобы обновить значение, когда что-то изменилось - как его реальная проблема имеет ценность, которую дорого рассчитать или что-то еще. – RichieHindle

6

Вам было бы лучше создать класс для этого в этом случае и использовать динамическое свойство. например .:

 

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

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

Это даст вам массу, объем и свойства плотности, где плотность рассчитывается на основе двух других значений. например

 

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 
 

Однако, если вы преданы, используя словарь, который вы, вероятно, следует расширить его и переопределить __getitem__ и __setitem__ «магические» методы для и определить, когда масса изменилась или иначе, когда плотность осуществляется доступ и пересчитывать по мере необходимости.

3

Проблема в том, что словари не являются подходящим инструментом для вашей проблемы. Ваш вопрос подобен «как я могу забить гвоздь с помощью отвертки» ;-)

Словари должны отображать ключи в значениях и не нуждаться в других значениях в словаре. То, что вы хотите это класс

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 

В этом примере пересчитывает плотность каждый раз, когда вы хотите получить его, купить можно также вычислить его в setMass и SetVolume функций.

1

Это так просто:

>>> 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 

Мои ссылки лямбда mydict и позже отыскивает новейшие данные держат в mydict, так избавляя меня от прохождения массы и объема функции каждый раз, когда я хочу назвать это, как и в вашем решении:

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']) 

Однако mydict [ «плотность»] является функцией, а не само значение.

+0

Хм - Я думаю, это было близко к тому, к чему я стремился, но я не хочу запускать функцию. Большая часть моего кода опирается на переменные в mydict, и когда я пишу новые вещи, это неизбежно, я забуду, что некоторые ключи должны быть выполнены, некоторые из них можно просто ссылаться. Спасибо за решение, хотя! – Dave

0

Самореферентный словарь почти соответствовал бы вашей второй попытке (с 7 лет назад) и прекрасно играл бы с любым другим кодом, который использует этот словарь. Другими словами, он все равно будет выглядеть и действовать как утка.

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

Смежные вопросы