用attrs定义的派生类init中参数的控制顺序

时间:2018-09-20 17:11:19

标签: python-attrs

attrs中,生成的init方法的参数顺序由类+ MRO(基于多个继承关系定义总顺序的标准方法)的属性定义顺序确定。 。这对我的用例不利,但似乎没有任何灵活性。这是用例:

我正在使用attrs定义一些建模图形基元的类。这些原语之间的联系是,它们都需要数据来处理并产生具有给定高度和宽度的图形,这些图形具有默认值。所以在顶层有一个课程

@attr.s
class BaseGraphics:
    data = attr.ib()
    height = attr.ib(default=300)
    width = attr.ib(default=400)

由此衍生出三个类,UnivariateGraphicsBivariateGraphicsMultivariateGraphicsdata中分别使用一,两或多个列。让我展示一个:

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

单变量案例仅具有x,而多变量案例则具有单个columns属性。之所以失败,是因为在MRO中,xyheightwidth之后,但是xy是强制性的,而height和{ width不是。确切的错误是

ValueError: No mandatory attributes allowed after an attribute with 
a default value or factory.  Attribute in question: 
Attribute(name='x', default=NOTHING, validator=None, repr=True, 
cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, 
converter=None, kw_only=False)

我可以像第一和第二列一样为xy设置一个默认值,但是顺序仍然是错误的。例如,如果想写类似的东西

BivariateGraphics(iris_data, "petalWidth", "sepalWidth")

第二和第三自变量将被解释为heightwidth,而不是xy。我可以通过将所有属性(仅data用作关键字)来防止出现此错误,但是我不支持此语法。通过阅读几个相关问题,例如#38,看来这是推荐的方法。关闭但没有雪茄。

另一种解决方法是将heightwidth独立地添加到每个派生类。这将违反DRY原则,并且无法表达和强制执行类之间的这种共性。有超过三个类,会变得非常讨厌。

这不仅仅是一个“学术”问题。我在attrs包中使用autosig,以帮助以一致的方式定义API。依次用于统计图形包altair_recipes中,实际上会发生上述情况(嗯,在下一发行版中,当我需要向所有图形基元中添加heightwidth时)。

我可以向开发人员提出问题,但由于主要开发人员在开玩笑(?)威胁以电击为基础的人,所以我认为这将是徒劳的。我会对基于非继承的解决方案感兴趣,该解决方案不需要DRY违反或重复。谢谢

2 个答案:

答案 0 :(得分:0)

我决定避免使用继承,而将其替换为在生成类之前起作用的组合器。为此,我使用了attr.make_class来代替类语法,OrderdDict将属性接受为OrderedDicts并遵守顺序。因此,上述组合器只是将npm install http-server 与某种约定组合以定义最终顺序的一种方式。不确定是否通过了变通方法级别来达到答案状态,但是这让我感动。

答案 1 :(得分:0)

在这种情况下,如果您希望能够依赖稳定的API(尤其是在子类化中,乍一看并不总是很清楚顺序),我们强烈建议使用类方法工厂(这也是我所使用的方法)倾向于在我自己的代码中使用)。每当您开始在类中更改内容时,事情都会变得混乱,尤其是当您必须浏览多个层次结构时。因此,最好以自己的方式构建API,并仅将attrs用于管道。

  

但是,由于主要开发者开玩笑(?)威胁以电击为基础的人

虽然我确实对子类化有很强的立场,但是我很难想象有记录要用电击威胁除我以外的任何人,除非它在志趣相投的朋友面前开玩笑。如果我确实有这样的判断力,我深表歉意。