gpt4 book ai didi

python-3.x - 抽象数据类的混合之间的冲突

转载 作者:行者123 更新时间:2023-12-05 02:33:24 24 4
gpt4 key购买 nike

1. 数据类混合问题,已解决

为了制作在 mypy 下进行类型检查的抽象数据类, 我将它们分为两个类,一个包含抽象方法,一个包含数据成员,如 this answer 中所述。抽象类继承自数据类。但是,当另一个抽象类和数据类对继承第一个时,这会遇到一个问题:“祖先”数据类的字段被“后代”清除。例如:

from dataclasses import dataclass
from abc import ABC, abstractmethod

@dataclass
class ADataclassMixin:
a_field: int = 1

class A(ADataclassMixin, ABC):
@abstractmethod
def method(self):
pass

@dataclass
#class BDataclassMixin(A): # works but fails mypy 0.931 type-check
class BDataclassMixin: # fails
b_field: int = 2
pass

class B(BDataclassMixin, A):
def method(self):
return self

o = B(a_field=5)

最后一行失败,产生此错误消息:

TypeError: BDataclassMixin.__init__() got an unexpected keyword argument 'a_field'

B 的方法解析顺序 (B.__mro__) 是 (B, BDataclassMixin, A, ADataclassMixin, ABC, object),正如预期的那样。但是找不到 a_field

一个解决方案,如上面注释掉的行所示,是将祖先类明确地放在后代数据类的声明中:class BDataclassMixin(A) 而不是 class BDataclassMixin。但是,这会导致类型检查失败,因为数据类只能是具体类。

2. 该解决方案存在 Unresolved 问题

如果我们添加第三个继承自 B 的类,上述解决方案将失效:

@dataclass
#class CDataclassMixin: # fails
class CDataclassMixin(A): # fails
#class CDataclassMixin(B, A): # works but fails type-check
c_field: int = 3
pass

class C(CDataclassMixin, B):
def method(self):
return "C's result"
pass

o = C(b_field=5)

现在,C 有a_fieldc_field 但失去了b_field

我发现如果我显式声明 CDataclassMixin 继承自 B 和 A(按此顺序),b_field 将与 a_field_ 和 c_field 一起出现在结果类中`。但是,在每个混合中明确声明继承层次结构会破坏混合的目的,即能够独立于所有其他混合对它们进行编码,并以您喜欢的任何方式轻松混合它们。

创建抽象数据类混合的正确方法是什么,以便从它们继承的类包含所有数据类字段?

最佳答案

正确的解决方案是放弃 DataclassMixin 类,简单地将抽象类变成数据类,如下所示:

@dataclass  # type: ignore[misc]
class A(ABC):
a_field: int = 1

@abstractmethod
def method(self):
pass

@dataclass # type: ignore[misc]
class B(A):
b_field: int = 2

@dataclass
class C(B):
c_field: int = 3

def method(self):
return self

失败的原因是,如 the documentation on dataclasses 中所述,数据类中的完整字段集是在编译数据类时确定的,而不是在继承数据类时确定的。生成数据类的 __init__ 函数的内部代码只能检查数据类的 MRO,因为它是自己声明的,不能在混合到另一个类中时检查。

有必要在每个抽象数据类的@dataclass行添加# type: ignore[misc],不是因为解错了,而是因为mypy 是错误的。 mypy, 不是 Python,它要求数据类是具体的。正如 ilevkivskyi 在 mypy issue 5374 中所解释的那样,问题是 mypy 希望数据类成为 Type 对象 and 每个 Type 对象都能够被实例化。这是一个已知问题,等待解决。

问题和解决方案中的行为正是数据类的行为方式。而且,令人高兴的是,以这种方式(普通方式)继承的抽象数据类可以随意混合到其他类中,与其他混合没有什么不同。

关于python-3.x - 抽象数据类的混合之间的冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70999513/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com