Как избежать циклических зависимостей при настройке свойств? - PullRequest
3 голосов
/ 31 марта 2012

Это принципиальный вопрос для классов, имеющих дело с математическими / физическими уравнениями, где пользователю разрешено устанавливать любой параметр, по которому рассчитываются остальные. В этом примере я хотел бы также иметь возможность установить частоту, избегая циклических зависимостей.

Например:

from traits.api import HasTraits, Float, Property
from scipy.constants import c, h
class Photon(HasTraits):
    wavelength = Float # would like to do Property, but that would be circular?
    frequency = Property(depends_on = 'wavelength')
    energy = Property(depends_on = ['wavelength, frequency'])
    def _get_frequency(self):
        return c/self.wavelength
    def _get_energy(self):
        return h*self.frequency

Мне также известна проблема синхронизации времени обновления, потому что я не знаю последовательность запуска обновлений:

  1. Изменяется длина волны
  2. Это вызывает обновление обеих зависимых объектов: частоты и энергии
  3. Но энергии необходимо обновлять частоту, чтобы энергия соответствовала новой длине волны!

(Ответ, который должен быть принят, должен также решить эту потенциальную проблему времени).

Итак, каков наилучший шаблон проектирования для решения этих взаимозависимых проблем? В конце я хочу, чтобы пользователь мог обновлять либо длину волны, либо частоту, а частота / длина волны и энергия должны обновляться соответствующим образом.

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

Пусть начнутся соревнования! ;)

Ответы [ 2 ]

2 голосов
/ 07 апреля 2012

Благодаря Адаму Хьюзу и Уоррену Векессеру из списка рассылки Enthought я понял, чего мне не хватало в моем понимании. Свойства на самом деле не существуют как атрибут. Теперь я рассматриваю их как нечто вроде «виртуального» атрибута, который полностью зависит от того, что делает писатель класса во время вызова _getter или _setter.

Поэтому, когда я хотел бы иметь возможность установить длину волны и частоту для пользователя, мне нужно только понять, что сама частота не существует в качестве атрибута и что вместо этого во время установки частоты мне нужно обновить «фундаментальную» 'атрибут длины волны, так что в следующий раз, когда требуется частота, она рассчитывается снова с новой длиной волны!

Мне также нужно поблагодарить пользователя sr2222, который заставил меня задуматься об отсутствующем кэшировании. Я понял, что зависимости, которые я установил с помощью ключевого слова 'depen_on', требуются только при использовании черты 'cached_property'. Если затраты на вычисление не так высоки или они выполняются не так часто, _getters и _setters позаботятся обо всем, что нужно, и не нужно использовать ключевое слово зависимость_ *. 1005 *

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

class Photon(HasTraits):
    wavelength = Float 
    frequency = Property
    energy = Property

    def _wavelength_default(self):
        return 1.0
    def _get_frequency(self):
        return c/self.wavelength
    def _set_frequency(self, freq):
        self.wavelength = c/freq
    def _get_energy(self):
        return h*self.frequency

Можно использовать этот класс так:

photon = Photon(wavelength = 1064)

или

photon = Photon(frequency = 300e6)

чтобы установить начальные значения и получить энергию сейчас, просто используйте ее напрямую:

print(photon.energy)

Обратите внимание, что метод _wavelength_default заботится о том случае, когда пользователь инициализирует экземпляр Photon без предоставления начального значения. Только для первого доступа к длине волны этот метод будет использоваться для его определения. Если бы я не сделал этого, первый доступ к частоте привел бы к вычислению 1/0.

0 голосов
/ 05 апреля 2012

Я бы порекомендовал научить ваше приложение, что из чего можно получить.Например, типичным случаем является то, что у вас есть набор из n переменных, и любая из них может быть получена из остальных.(Конечно, вы можете моделировать и более сложные случаи, но я бы не стал это делать, пока вы не столкнетесь с такими случаями).* Это всего лишь эскиз, я не проверял и не продумывал все возможные проблемы.

...