我目前正在尝试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
我怎么解决这个问题?
在发现数据类可能会获得一个允许字段重新排序的装饰器参数后,我回到了这个问题。这无疑是一个有希望的发展,尽管这一功能的进展似乎有些停滞。
现在,您可以通过使用dataclassy(我对数据类的重新实现,克服了这种挫折)来获得这种行为,以及其他一些细节。在原始示例中使用from dataclassy来代替from dataclassy意味着它运行时没有错误。
使用inspect打印Child的签名使正在发生的事情变得清晰;结果是(name: str, age: int, school: str, ugly: bool = True)。字段总是重新排序,以便在初始化式的参数中,具有默认值的字段位于不具有默认值的字段之后。两个列表(没有默认值的字段和有默认值的字段)仍然按照定义顺序排序。
面对这个问题是促使我编写数据类替代品的因素之一。这里详细介绍的变通方法虽然很有用,但要求将代码扭曲到完全否定数据类的简单方法(即字段顺序可以简单地预测)所提供的可读性优势的程度。
一种可行的解决方法是使用monkey-patch来附加父字段
import dataclasses as dc
def add_args(parent):
def decorator(orig):
"Append parent's fields AFTER orig's fields"
# Aggregate fields
ff = [(f.name, f.type, f) for f in dc.fields(dc.dataclass(orig))]
ff += [(f.name, f.type, f) for f in dc.fields(dc.dataclass(parent))]
new = dc.make_dataclass(orig.__name__, ff)
new.__doc__ = orig.__doc__
return new
return decorator
class Animal:
age: int = 0
@add_args(Animal)
class Dog:
name: str
noise: str = "Woof!"
@add_args(Animal)
class Bird:
name: str
can_fly: bool = True
Dog("Dusty", 2) # --> Dog(name='Dusty', noise=2, age=0)
b = Bird("Donald", False, 40) # --> Bird(name='Donald', can_fly=False, age=40)
也可以预先添加非默认字段,
通过检查f.default是否为dc。失踪,
但这可能太脏了。
虽然猴子补丁缺乏遗传的一些特征,
它仍然可以用于向所有伪子类添加方法。
对于更细粒度的控制,请设置默认值
使用直流。字段(compare=False, repr=True,…)