设置属性时如何避免循环依赖? [英] How to avoid circular dependencies when setting Properties?

查看:21
本文介绍了设置属性时如何避免循环依赖?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个设计原则问题,适用于处理数学/物理方程的课程,其中允许用户设置计算剩余部分的任何参数.在这个例子中,我希望能够在避免循环依赖的同时设置频率.

This is a design principle question for classes dealing with mathematical/physical equations where the user is allowed to set any parameter upon which the remaining are being calculated. In this example I would like to be able to let the frequency be set as well while avoiding circular dependencies.

例如:

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

我也知道这里有一个更新触发时间问题,因为我不知道触发更新的顺序:

I'm also aware of an update trigger timing problem here, because I don't know the sequence the updates will be triggered:

  1. 波长正在改变
  2. 这会触发两个依赖实体的更新:频率和能量
  3. 但是能量需要更新频率,以便能量具有适合新波长的值!

(被接受的答案还应该解决这个潜在的时间问题.)

(The answer to be accepted should also address this potential timing problem.)

那么,解决这些相互依赖的问题的最佳设计模式是什么?最后,我希望用户能够更新波长或频率,频率/波长和能量也应相应更新.

So, what' the best design pattern to get around these inter-dependent problems? At the end I want the user to be able to update either wavelength or frequency and frequency/wavelength and energy shall be updated accordingly.

这种问题当然会出现在所有试图处理方程的类中.

This kind of problems of course do arise in basically all classes that try to deal with equations.

比赛开始!;)

推荐答案

感谢来自 Enthought 邮件列表的 Adam Hughes 和 Warren Weckesser,我意识到我的理解中缺少什么.属性并不真正作为属性存在.我现在将它们视为虚拟"属性,完全取决于类的作者在调用 _getter 或 _setter 时所做的事情.

Thanks to Adam Hughes and Warren Weckesser from the Enthought mailing list I realized what I was missing in my understanding. Properties do not really exist as an attribute. I now look at them as something like a 'virtual' attribute that completely depends on what the writer of the class does at the time a _getter or _setter is called.

因此,当我希望能够由用户设置波长和频率时,我只需要了解频率本身不作为属性存在,而是在频率的 _setting 时间我需要更新基本'属性波长,以便下次需要频率时,用新的波长重新计算!

So when I would like to be able to set wavelength AND frequency by the user, I only need to understand that frequency itself does not exist as an attribute and that instead at _setting time of the frequency I need to update the 'fundamental' attribute wavelength, so that the next time the frequency is required, it is calculated again with the new wavelength!

我还要感谢用户 sr2222,他让我想到了缺失的缓存.我意识到我使用关键字 'depends_on' 设置的依赖项仅在使用 'cached_property' Trait 时才需要.如果计算的成本不是那么高,或者不是经常执行,_getter 和 _setter 会处理你需要的一切,不需要使用 'depends_on' 关键字.

I also need to thank the user sr2222 who made me think about the missing caching. I realized that the dependencies I set up by using the keyword 'depends_on' are only required when using the 'cached_property' Trait. If the cost of calculation is not that high or it's not executed that often, the _getters and _setters take care of everything that one needs and one does not need to use the 'depends_on' keyword.

现在这里是我正在寻找的简化解决方案,它允许我设置波长或频率而无需循环:

Here now the streamlined solution I was looking for, that allows me to set either wavelength or frequency without circular loops:

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

人们会像这样使用这个类:

One would use this class like this:

photon = Photon(wavelength = 1064)

photon = Photon(frequency = 300e6)

设置初始值并获取现在的能量,直接使用即可:

to set the initial values and to get the energy now, one just uses it directly:

print(photon.energy)

请注意,_wavelength_default 方法会处理用户在不提供初始值的情况下初始化 Photon 实例的情况.只有第一次访问波长时,才会使用此方法来确定它.如果我不这样做,第一次访问频率将导致 1/0 计算.

Please note that the _wavelength_default method takes care of the case when the user initializes the Photon instance without providing an initial value. Only for the first access of wavelength this method will be used to determine it. If I would not do this, the first access of frequency would result in a 1/0 calculation.

这篇关于设置属性时如何避免循环依赖?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆