放弃Python 2后从attrs迁移至dataclasses,如何保留字段自动转换API?
如何在dataclasses中实现类似attrs转换器的灵活字段转换?
当然可以!完全能在Python 3的dataclasses里复刻attrs转换器的功能,让你的冻结类依然支持接受list、set、dict_keys等多种可迭代类型,自动转成tuple。我给你两种实用的实现方式:
方法一:用__post_init__直接处理转换
这是最直接的方案,利用dataclasses自带的__post_init__钩子——它会在实例初始化完成后自动调用,刚好适合做字段的后处理。因为是冻结类,不能直接给字段赋值,所以要用object.__setattr__来绕过冻结限制:
from dataclasses import dataclass @dataclass(frozen=True, eq=True) class MyClass: my_field: tuple = tuple() def __post_init__(self): # 将传入的任何可迭代对象转为tuple converted_field = tuple(self.my_field) # 冻结类必须用object.__setattr__修改字段 object.__setattr__(self, 'my_field', converted_field)
测试一下效果,和你之前attrs的代码完全一致:
print(MyClass([1, 2, 3])) # 输出: MyClass(my_field=(1, 2, 3)) print(MyClass({2, 1, 3})) # 输出: MyClass(my_field=(1, 2, 3))(set无序,转换后顺序不确定) print(MyClass(dict.fromkeys(['x', 'y']).keys())) # 输出: MyClass(my_field=('x', 'y'))
而且因为设置了frozen=True,dataclasses会自动生成合法的__hash__方法(只要eq=True,这是冻结类的默认值),所以你的类依然是可哈希的,和之前attrs的hash=True效果一样。
方法二:封装转换器函数,提升可维护性
如果以后需要修改转换逻辑(比如要过滤掉空值),可以把转换逻辑封装成单独的函数,让代码更清晰:
from dataclasses import dataclass, field def to_tuple(value): # 这里可以扩展转换逻辑,比如过滤None值 return tuple(item for item in value if item is not None) @dataclass(frozen=True, eq=True) class MyClass: my_field: tuple = field(default_factory=tuple) def __post_init__(self): converted = to_tuple(self.my_field) object.__setattr__(self, 'my_field', converted)
这样后续调整转换规则时,只需要修改to_tuple函数即可,不用动类的内部逻辑。
内容的提问来源于stack exchange,提问作者Campi
相关产品推荐
相关产品推荐

