修改其他属性的属性

attributes that modify other attributes

我想制作一个具有以下行为的 Block class:如果设置了 iip3,则 oip3 设置为 iip3 + gain。如果设置了 oip3,则 iip3 设置为 oip3 - 增益如下:

b = Block(gain = 10)
Block(gain=10, iip3=inf, oip3=inf)

b.oip3 = 30
Block(gain=10, iip3=20, oip3=30)

b.iip3 = 21
Block(gain=10, iip3=21, oip3=31)

我已经用 attrs 模块试过了:

import attr
import numpy as np

def set_oip3(instance, attribute, iip3):
    instance.oip3 = iip3 + instance.gain
    return iip3

def set_iip3(instance, attribute, oip3):
    instance.iip3 = oip3 - instance.gain
    return oip3

@attr.s
class Block:

    gain = attr.ib()
    iip3 = attr.ib(on_setattr=set_oip3, default=np.inf)
    oip3 = attr.ib(on_setattr=set_iip3, default=np.inf)

但是,这不起作用。我怀疑对 set_oip3 的调用会导致对 set iip3 的调用,而 iip3 又会调用 set oip3.

必须有一个使用 attrs 的解决方案。

您可以使用 @property 装饰器:

import numpy as np


class Block:
    def __init__(self, gain=10, iip3=np.inf, oip3=np.inf):
        self.gain = gain
        self._iip3 = iip3
        self._oip3 = oip3

    def __repr__(self):
        return f"Block(gain={self.gain}, iip3={self.iip3}, oip3={self.oip3})"

    @property
    def iip3(self):
        return self._iip3

    @iip3.setter
    def iip3(self, val):
        self._iip3 = val
        self._oip3 = self._iip3 + self.gain

    @property
    def oip3(self):
        return self._oip3

    @oip3.setter
    def oip3(self, val):
        self._oip3 = val
        self._iip3 = self._oip3 - self.gain

用法:

In [2]: b = Block()

In [3]: b.iip3 = 21

In [4]: b
Out[4]: Block(gain=10, iip3=21, oip3=31)

In [5]: b.oip3 = 30

In [6]: b
Out[6]: Block(gain=10, iip3=20, oip3=30)

就其价值而言,让增变器对给定增变器应该修改的属性以外的属性产生副作用并不是一个好主意。

正如其他人所说,在属性更改时改变属性并不是一个好主意。但是如果你坚持,你可以通过使用 object.__setattr__ 来绕过 on_setattr 钩子——这也是 attrs 在内部做的事情:

import attr
import numpy as np

def set_oip3(instance, attribute, iip3):
    object.__setattr__(instance, "oip3", iip3 + instance.gain)
    return iip3

def set_iip3(instance, attribute, oip3):
    object.__setattr__(instance, "iip3", oip3 - instance.gain)
    return oip3

@attr.define
class Block:

    gain = attr.ib()
    iip3 = attr.ib(on_setattr=set_oip3, default=np.inf)
    oip3 = attr.ib(on_setattr=set_iip3, default=np.inf)

按照您的要求工作:

In [9]: b = Block(gain = 10)

In [10]: b
Out[10]: Block(gain=10, iip3=inf, oip3=inf)

In [11]: b.oip3 = 30

In [12]: b
Out[12]: Block(gain=10, iip3=20, oip3=30)

In [13]: b.iip3 = 21

In [14]: b
Out[14]: Block(gain=10, iip3=21, oip3=31)