在attrs
中,生成的init
方法的参数顺序由类+ MRO(基于多个继承关系定义总顺序的标准方法)的属性定义顺序确定。 。这对我的用例不利,但似乎没有任何灵活性。这是用例:
我正在使用attrs
定义一些建模图形基元的类。这些原语之间的联系是,它们都需要数据来处理并产生具有给定高度和宽度的图形,这些图形具有默认值。所以在顶层有一个课程
@attr.s
class BaseGraphics:
data = attr.ib()
height = attr.ib(default=300)
width = attr.ib(default=400)
由此衍生出三个类,UnivariateGraphics
,BivariateGraphics
和MultivariateGraphics
在data
中分别使用一,两或多个列。让我展示一个:
@attr.s
class BivariateGraphics(BaseGraphics):
x = attr.ib()
y = attr.ib()
单变量案例仅具有x
,而多变量案例则具有单个columns
属性。之所以失败,是因为在MRO中,x
和y
在height
和width
之后,但是x
和y
是强制性的,而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)
我可以像第一和第二列一样为x
和y
设置一个默认值,但是顺序仍然是错误的。例如,如果想写类似的东西
BivariateGraphics(iris_data, "petalWidth", "sepalWidth")
第二和第三自变量将被解释为height
和width
,而不是x
和y
。我可以通过将所有属性(仅data
用作关键字)来防止出现此错误,但是我不支持此语法。通过阅读几个相关问题,例如#38,看来这是推荐的方法。关闭但没有雪茄。
另一种解决方法是将height
和width
独立地添加到每个派生类。这将违反DRY原则,并且无法表达和强制执行类之间的这种共性。有超过三个类,会变得非常讨厌。
这不仅仅是一个“学术”问题。我在attrs
包中使用autosig
,以帮助以一致的方式定义API。依次用于统计图形包altair_recipes
中,实际上会发生上述情况(嗯,在下一发行版中,当我需要向所有图形基元中添加height
和width
时)。
我可以向开发人员提出问题,但由于主要开发人员在开玩笑(?)威胁以电击为基础的人,所以我认为这将是徒劳的。我会对基于非继承的解决方案感兴趣,该解决方案不需要DRY违反或重复。谢谢
答案 0 :(得分:0)
我决定避免使用继承,而将其替换为在生成类之前起作用的组合器。为此,我使用了attr.make_class
来代替类语法,OrderdDict
将属性接受为OrderedDicts
并遵守顺序。因此,上述组合器只是将npm install http-server
与某种约定组合以定义最终顺序的一种方式。不确定是否通过了变通方法级别来达到答案状态,但是这让我感动。
答案 1 :(得分:0)
在这种情况下,如果您希望能够依赖稳定的API(尤其是在子类化中,乍一看并不总是很清楚顺序),我们强烈建议使用类方法工厂(这也是我所使用的方法)倾向于在我自己的代码中使用)。每当您开始在类中更改内容时,事情都会变得混乱,尤其是当您必须浏览多个层次结构时。因此,最好以自己的方式构建API,并仅将attrs用于管道。
但是,由于主要开发者开玩笑(?)威胁以电击为基础的人
虽然我确实对子类化有很强的立场,但是我很难想象有记录要用电击威胁除我以外的任何人,除非它在志趣相投的朋友面前开玩笑。如果我确实有这样的判断力,我深表歉意。