3

使用 Python 模块 attrs,我试图创建一个子类,其属性条件比其父类更严格,如下面的最小示例所示。

import attr

@attr.s
class Base:
    x = attr.ib()
    y = attr.ib()

@attr.s
class Child(Base):

    @x.validator
    def _x_validator(self, a, x):
        if x < 0:
            raise ValueError()

像上面那样定义验证器会引发错误(NameError: name 'x' is not defined)。

我通过x在子类中重新定义找到了一种解决方法。

@attr.s
class Child(Base):
    x = attr.ib()

    @x.validator
    def _x_validator(self, a, x):
        if x < 0:
            raise ValueError()

但是它打乱了属性的顺序。

In [5]: Child(5, 10)
Out[5]: Child(y=5, x=10)

所以,最后,我最终重新定义了子类中的所有属性(实际代码中不止两个)。

有没有更优雅的方法来做到这一点?

4

1 回答 1

2

最后,我发现的最简单的解决方法就是不在子类中使用验证器:

@attr.s
class Child(Base):
    def __attrs_post_init__(self):
        assert self.x > 0

感谢 bruno desthuilliers 正确地指出了 Liskov 原则。请注意,该问题不仅发生在@x.validator其他构造上,例如属性默认值也发生@x.default。似乎即将推出dataclass的 Python 3.7在继承方面比在这种情况下工作得更好。attrs

于 2018-03-12T10:40:50.337 回答