构建变量依赖

Building variable dependencies

我正在尝试在 Python 中构建一些变量依赖项。例如,如果 a = xb = yc = a + b,那么如果 ab 更改 c 的值应该自动更新。我知道 Python 变量和值基于标签工作,并且一直在尝试使用 __setattr__ 解决这个问题。由于 __setattr__.

中的循环依赖,我似乎在执行此操作时遇到了一些麻烦

考虑这个小代码片段:

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__ 已被覆盖并为每个正在创建的值调用, __setattr__ 中的 if 检查会抛出一个错误,指出还没有找到剩余的三个变量(这是真的,因为它们还没有被创建)。

如何解决这种依赖关系?

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

假设您希望未设置的 _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