我目前正在尝试Python 3.7中引入的新数据类构造。我目前一直在尝试继承父类。看起来参数的顺序被我当前的方法弄糟了,以至于子类中的bool参数在其他参数之前被传递。这会导致类型错误。
from dataclasses import dataclass
@dataclass
class Parent:
name: str
age: int
ugly: bool = False
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
def print_id(self):
print(f'The Name is {self.name} and {self.name} is {self.age} year old')
@dataclass
class Child(Parent):
school: str
ugly: bool = True
jack = Parent('jack snr', 32, ugly=True)
jack_son = Child('jack jnr', 12, school = 'havard', ugly=True)
jack.print_id()
jack_son.print_id()
当我运行这段代码时,我得到这个TypeError
:
TypeError: non-default argument 'school' follows default argument
我该怎么解决?
基于Martijn Pieters的解决方案,我做了以下工作:
1)创建一个实现post_init的混合
2)然后在存在继承问题的类中:
数据类组合属性的方式使您无法在基类中使用具有默认值的属性,然后在子类中使用不具有默认值(位置属性)的属性。
这是因为属性是从MRO的底部开始组合的,并按照第一个看到的顺序构建属性的有序列表;覆盖保留在其原始位置。所以
Parent
以['name', 'age', 'ugly']
开始,其中ugly
有默认值,然后Child
将['school']
添加到列表的末尾(列表中已经有ugly
)。这意味着您以['name', 'age', 'ugly', 'school']
结束,并且由于school
没有默认值,这将导致__init__
的参数列表无效。这记录在PEP-557 Dataclasses中的inheritance下:
在Specification下:
你在这里有一些选择来避免这个问题。
第一个选项是使用单独的基类将具有默认值的字段强制放到MRO顺序的后面位置。无论如何,避免直接在要用作基类的类(如
Parent
)上设置字段。以下类层次结构有效:
通过将字段拖出到separate基类(具有不带默认值的字段和具有默认值的字段)中,并按照精心选择的继承顺序,可以生成一个MRO,将所有不带默认值的字段放在具有默认值的字段之前。
Child
的反向MRO(忽略object
)是:请注意,
Parent
不设置任何新字段,因此在这里,它以字段列表顺序的“最后一个”结束并不重要。具有不带默认值的字段的类(_ParentBase
和_ChildBase
)先于具有默认值的字段的类(_ParentDefaultsBase
和_ChildDefaultsBase
)。结果是
Parent
和Child
类具有一个旧字段,而Child
仍然是Parent
的一个子类:因此您可以创建两个类的实例:
另一个选项是只使用具有默认值的字段;您仍然可以在错误中设置为不提供
school
值,方法是在__post_init__
中增加一个值:但是这个确实改变了字段顺序;之后结束:
school
在^{类型提示检查器会抱怨
_no_default
不是字符串。您还可以使用^{} project ,它是激发
dataclasses
灵感的项目。它使用不同的继承合并策略;它将子类中的重写字段拉到字段列表的末尾,因此Parent
类中的['name', 'age', 'ugly']
变成Child
类中的['name', 'age', 'school', 'ugly']
;通过使用默认值重写字段,attrs
允许重写,而无需执行MRO舞蹈。attrs
支持定义不带类型提示的字段,但让我们通过设置auto_attribs=True
来坚持supported type hinting mode:您看到此错误是因为在具有默认值的参数之后添加了一个没有默认值的参数。继承字段插入数据类的顺序与Method Resolution Order相反,这意味着
Parent
字段排在第一位,即使它们稍后被其子级重写。来自PEP-557 - Data Classes的示例:
不幸的是,我认为没有办法解决这个问题。我的理解是,如果父类有默认参数,那么子类就不能有非默认参数。
相关问题 更多 >
编程相关推荐