mypy v0.910 拒绝 Python 3.9 中的抽象数据类。这是最小的可重复示例:
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class Liquid(ABC):
@abstractmethod
def drip(self) -> None:
pass
Run Code Online (Sandbox Code Playgroud)
这是错误消息:
$ mypy --python-version 3.9 so.py
so.py:4: error: Only concrete class can be given where "Type[Liquid]" is expected
Found 1 error in 1 file (checked 1 source file)
Run Code Online (Sandbox Code Playgroud)
如何让此代码通过mypy?
笔记
我从mypy 问题 #5374中了解到,这是mypy中的一个错误,于 2018 年首次注意到,但仍未得到纠正。不过,我认为人们必须将mypy与抽象数据类一起使用,因此必须有一种解决方法或正确的方法来定义或注释该类。有什么推荐的?
错误消息的基础似乎是mypy假设任何类型的对象都Type可以实例化,但抽象类不能实例化。这似乎是错误,因为Type被定义为表示类对象,而不一定是具体的类对象(即可以实例化的类对象)。
添加# type: ignore到包含的行 …
python abstract-base-class mypy python-dataclasses python-typing
假设您已经定义了一个 Python 数据类:
@dataclass
class Marker:
a: float
b: float = 1.0
Run Code Online (Sandbox Code Playgroud)
将值从一个实例复制marker_a到另一个实例的最简单方法是marker_b什么?
这是我尝试实现的目标的示例:
marker_a = Marker(1.0, 2.0)
marker_b = Marker(11.0, 12.0)
# now some magic happens which you hopefully can fill in
print(marker_b)
# result: Marker(a=1.0, b=2.0)
Run Code Online (Sandbox Code Playgroud)
作为边界条件,我不想创建新实例并将其分配给marker_b. 好的,我可以遍历所有定义的字段并一个一个复制值,但我想必须有一种更简单的方法。
我有一个父数据类和一个子数据类继承第一个类。我__eq__()在父数据类中重新定义了方法。但是当我比较对象子数据类时,它不使用__eq__()父数据类中定义的方法。为什么会发生这种情况?我怎样才能解决这个问题?
微量元素:
from dataclasses import dataclass
@dataclass
class A:
name: str
field1: str = None
def __eq__(self, other):
print('A class eq')
return self.name == other.name
@dataclass
class B(A):
field2: str = None
b1 = B('b', 'b1')
b2 = B('b', 'b2')
print(b1 == b2)
Run Code Online (Sandbox Code Playgroud) 我希望对某些字典执行静态类型检查( pylancein )。vscode“棘手”的部分是我希望一些参数是可选的并且根本不显示在字典中。我尝试过使用dataclassesandTypedDict但到目前为止还没有运气。
from typing import Optional, List
from dataclasses import dataclass, asdict
@dataclass
class SubOrder:
name: str
@dataclass
class Order:
name: str
sub_orders: Optional[List[SubOrder]]
assert asdict(Order(name="Pizza")) == {"name": "Pizza"}
assert asdict(Order(name="Pizza", sub_orders=[SubOrder(name="Pasta")])) == {
"name": "Pizza",
"sub_orders": [{"name": "Pasta"}],
}
Run Code Online (Sandbox Code Playgroud)
这是可以实现的吗dataclasses?我基本上只是希望我的静态类型检查器 ( pylance/ pyright) 来检查我的字典,这就是我使用dataclasses. 我也尝试过TypedDict,但类型检查器的行为似乎不像我那样。他们总是要求我设置sub_orders。
以下代码通过了,但pylance对没有 感到不满意sub_orders。
from typing import Optional, List, TypedDict
class SubOrder(TypedDict):
name: str …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 backport 包将我们的命名元组类移植到 Python 3.6 中的数据类中。但是,我注意到在模拟数据类时,您不能再使用“spec”关键字。我认为这是因为数据类代码是自动生成的。
from dataclasses import dataclass
import mock
@dataclass
class A:
aaa: str
bbb: int
m = mock.Mock(spec=A)
m.aaa
Run Code Online (Sandbox Code Playgroud)
这是我得到的错误:
AttributeError: Mock object has no attribute 'aaa'
Run Code Online (Sandbox Code Playgroud)
知道是否有任何方法可以自动将原始对象的所有属性设置为模拟对象?我有很多包含大量数据的数据类。如果我尝试一一手动设置这些值,那将非常乏味。
假设class A有一个类型为的成员class B,并且class B有一个类型为的成员class A.
在Scala或Kotlin中,您可以按任何顺序定义类,而不必担心在这种情况下,因为第一个定义的类可以像往常一样使用第二个定义的类,即使在case/data类中也是如此.
但是在Python中,以下代码
class A:
b = B()
class B:
a = A()
Run Code Online (Sandbox Code Playgroud)
抛出编译错误,因为class B在定义时class A未定义.
你可以解决这个简单的案例,就像在这个答案中一样
class A:
pass
class B:
a = A()
A.b = B()
Run Code Online (Sandbox Code Playgroud)
但是,这种方式对Python中的数据类不起作用,因为在定义数据类之后分配成员不会更新数据类的自动生成方法,这使得"数据类"的使用变得无用.
@dataclass
class A:
b: B # or `b: Optional[B]`
@dataclass
class B:
a: A # or `a: Optional[A]`
Run Code Online (Sandbox Code Playgroud)
我该如何避免这个问题?
我需要 进一步回答有关使 Python json 编码器支持 Python 的新数据类的问题:考虑它们何时处于嵌套结构json serialization of @dataclass中。
考虑:
import json
from attr import dataclass
from dataclasses_json import dataclass_json
@dataclass
@dataclass_json
class Prod:
id: int
name: str
price: float
prods = [Prod(1,'A',25.3),Prod(2,'B',79.95)]
pjson = json.dumps(prods)
Run Code Online (Sandbox Code Playgroud)
这给了我们:
TypeError: Object of type Prod is not JSON serializable
Run Code Online (Sandbox Code Playgroud)
请注意,上面确实包含了答案之一/sf/answers/4178169831/。它声称通过装饰器支持嵌套案例dataclass_json。显然这实际上行不通。
我还尝试了另一个答案/sf/answers/3590072461/:
class EnhancedJSONEncoder(json.JSONEncoder):
def default(s, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
Run Code Online (Sandbox Code Playgroud)
我为它创建了一个辅助方法:
def jdump(s,foo):
return json.dumps(foo, cls=s.c.EnhancedJSONEncoder)
Run Code Online (Sandbox Code Playgroud)
但使用该方法也不会影响(错误)结果。还有其他提示吗?
假设我在python3中有一个数据类。我希望能够哈希和排序这些对象。
我只希望它们在ID上排序/散列。
我在文档中看到,我可以只实现__hash__,但我想让datacalses为我完成工作,因为它们旨在处理此问题。
from dataclasses import dataclass, field
@dataclass(eq=True, order=True)
class Category:
id: str = field(compare=True)
name: str = field(default="set this in post_init", compare=False)
a = sorted(list(set([ Category(id='x'), Category(id='y')])))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Category'
Run Code Online (Sandbox Code Playgroud) 我所知道
的 Python 数据类允许使用数据类或类进行继承。在最佳实践中(以及在其他语言中),当我们进行继承时,应该首先调用初始化。在 Python 中它是:
def __init__(self):
super().__init__()
...
Run Code Online (Sandbox Code Playgroud)
我在做什么
因为数据类是在 Python 3.7 中引入的,所以我正在考虑用数据类替换我的所有类。使用 dataclass,它的好处之一是__init__为您生成。当数据类需要继承基类时,这并不好——例如:
class Base:
def __init__(self):
self.a = 1
@dataclass
class Child(Base):
a:int
def __post_init__(self):
super().__init__()
Run Code Online (Sandbox Code Playgroud)
我的问题
问题是我们必须将超级初始化调用放入__post_init__其中,实际上是在dataclass 的init之后调用的。
缺点是我们失去了约定契约,初始化混乱导致我们无法覆盖超类的属性。
可以通过 的概念解决__pre_init__。我已经阅读了该文档,但没有看到与该概念有任何关系。我错过了什么吗?
from typing import Optional
@dataclass
class Event:
id: str
created_at: datetime
updated_at: Optional[datetime]
#updated_at: datetime = field(default_factory=datetime.now) CASE 1
#updated_at: Optional[datetime] = None CASE 2
@dataclass
class NamedEvent(Event):
name: str
Run Code Online (Sandbox Code Playgroud)
创建事件实例时,我通常不会有updated_at字段。current time在数据库中进行插入时,我可以传递作为默认值或添加一个值,并在对象的后续使用中获取它。哪种方法更好?根据我的理解,我无法在不通过case1 和 case2 中的 updated_at字段的NamedEvent情况下创建实例,因为我在 name 字段中没有默认值。
python ×10
python-3.x ×3
inheritance ×2
attributes ×1
hash ×1
mocking ×1
mypy ×1
pyright ×1
python-3.7 ×1