1

我想创建一个Block具有以下行为的类:如果设置了 iip3,则将 oip3 设置为 iip3 + 增益。如果设置了 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,而后者又调用 set oip3。

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

4

2 回答 2

2

您可以使用@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)

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

于 2021-10-05T01:08:41.623 回答
1

正如其他人所说,在属性更改时改变属性并不是一个好主意。但是如果你坚持,你可以on_setattr通过使用来规避钩子object.__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)
于 2021-10-05T08:21:41.417 回答