【问题标题】:Building variable dependencies构建变量依赖
【发布时间】:2015-06-01 08:25:11
【问题描述】:

我正在尝试在 Python 中构建一些变量依赖项。例如,如果a = xb = yc = a + b,那么如果ab 更改了c 的值,则应自动更新。我知道 Python 变量和值是基于标签工作的,并且一直在尝试使用 __setattr__ 来解决这个问题。由于__setattr__ 中的循环依赖,我似乎在执行此操作时遇到了一些麻烦。

考虑一下这个小代码sn-p:

class DelayComponents(object):
    '''
    Delay Components Class
    '''

    def __init__(self, **delays):
        '''
        Constructor
        '''
        self.prop_delay = round(float(delays['prop_delay']), 2)
        self.trans_delay = round(float(delays['trans_delay']), 2)
        self.proc_delay = round(float(delays['proc_delay']), 2)
        self.queue_delay = round(float(delays['queue_delay']), 2)
        self.delay = (self.prop_delay + self.proc_delay +
                      self.trans_delay + self.queue_delay)

    def __setattr__(self, key, value):
        self.__dict__[key] = value
        if (key in ("prop_delay", "trans_delay",
                    "proc_delay", "queue_delay")):
            self.delay = (self.prop_delay + self.proc_delay +
                      self.trans_delay + self.queue_delay)

这似乎很好地达到了目的,但是当我第一次创建 DelayComponents 的对象时,由于 __setattr__ 已被覆盖并为正在创建的每个值调用,if 检查里面__setattr__ 抛出一个错误,指出尚未找到剩余的三个变量(这是真的,因为它们尚未创建)。

如何解决这种依赖关系?

另外,有什么方法可以用dict 完成同样的事情吗?更具体地说,如果三个变量实际上是字典中的键值对,其中第三个键的值是前两个键的值的总和,那么当前两个键中的任何一个时,是否可以自动更新第三个值变化?

【问题讨论】:

  • 你可以使用例如sympy 设置和管理方程式。
  • @jonrsharpe 我不明白 SymPy 如何帮助我自动解决依赖关系。如果我正确理解了文档,您仍然需要对方程执行solve()。您能否更具体地说明您的建议?

标签: python python-3.x dependencies


【解决方案1】:

假设您希望未设置的 _delays(__init____setattr__)的默认值为零,您可以执行以下操作:

class DelayComponents(object):
    '''
    Delay Components Class
    '''

    ATTRS = ['prop_delay', 'trans_delay', 'proc_delay', 'queue_delay']

    def __init__(self, **delays):
        '''
        Constructor
        '''
        for attr in self.ATTRS:
            setattr(self, attr, round(float(delays.get(attr, 0)), 2))
        # No point in setting delay here - it's already done!

    def __setattr__(self, key, value):
        super(DelayComponents, self).__setattr__(key, value)
        # This avoids directly interacting with the __dict__
        if key in self.ATTRS:
            self.delay = sum(getattr(self, attr, 0) for attr in self.ATTRS)

使用中:

>>> d = DelayComponents(prop_delay=1, trans_delay=2, proc_delay=3, queue_delay=4)
>>> d.delay
10.0

如果您想要不同属性的不同默认值,DelayComponents.ATTRS 可以是字典 {'attribute_name': default_value, ...}


一个更简单的替代方法是将delay 设为@property,它只根据需要进行计算:

class DelayComponents(object):
    '''
    Delay Components Class
    '''

    ATTRS = ['prop_delay', 'trans_delay', 'proc_delay', 'queue_delay']

    def __init__(self, **delays):
        '''
        Constructor
        '''
        for attr in self.ATTRS:
            setattr(self, attr, round(float(delays.get(attr, 0)), 2))

    @property
    def delay(self):
        return sum(getattr(self, attr, 0) for attr in self.ATTRS)

回答您的子问题:不,没有办法用香草dict 做到这一点;不会根据计算它们的值的变化来重新评估键的值。


另外,说真的,您当前的文档字符串没有任何意义;您不妨将它们完全排除在外。它们不提供任何信息,也不符合PEP-257

【讨论】:

  • 非常感谢您的清晰解释。而且我的文档字符串没有被用于任何事情。这只是测试代码。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多