非特定数据类实例的类型提示 [英] type hint for an instance of a non specific dataclass
问题描述
我有一个函数可以接受任何 dataclass
的实例.什么是合适的类型提示?
I have a function that accepts an instance of any dataclass
.
what would be an appropriate type hint for it ?
在python文档中没有找到官方的内容
haven't found something official in the python documentation
这是我一直在做的,但我认为这是不正确的
this is what I have been doing, but i don't think it's correct
from typing import Any, NewType
DataClass = NewType('DataClass', Any)
def foo(obj: DataClass):
...
另一个想法是使用协议
具有这些类属性 __dataclass_fields__
、__dataclass_params__
.
推荐答案
尽管名称如此,dataclasses.dataclass
并未公开类接口.它只是允许您以一种方便的方式声明一个自定义类,这使得它显然将用作数据容器.因此,理论上,几乎没有机会编写仅适用于数据类的东西,因为数据类实际上只是普通类.
Despite its name, dataclasses.dataclass
doesn't expose a class interface. It just allows you to declare a custom class in a convenient way that makes it obvious that it is going to be used as a data container. So, in theory, there is little opportunity to write something that only works on dataclasses, because dataclasses really are just ordinary classes.
在实践中,您无论如何要声明仅用于数据类的函数有几个原因,我看到了两种方法.
In practice, there a couple of reasons why you would want to declare dataclass-only functions anyway, and I see two ways to go about it.
正确方式,使用静态类型检查器并编写协议
The right way, using a static type checker and writing a Protocol
from dataclasses import dataclass
from typing import Dict
from typing_extensions import Protocol
class IsDataclass(Protocol):
# as already noted in comments, checking for this attribute is currently
# the most reliable way to ascertain that something is a dataclass
__dataclass_fields__: Dict
def dataclass_only(x: IsDataclass):
... # do something that only makes sense with a dataclass
@dataclass
class A:
pass
dataclass_only(A()) # a static type check should show that this line is fine
您在问题中也提到了这种方法,但它有三个缺点:
This approach is also what you alluded to in your question, but it has three downsides:
- 您需要一个第三方库,例如
mypy
来执行为您进行静态类型检查 - 如果您使用的是 python 3.7 或更早版本,则需要手动安装
typing_extensions
也是如此,因为Protocol
不是其中的核心typing
模块 - 最后但并非最不重要的一点是,以这种方式使用数据类协议现在不起作用一个>
- You need a third party library such as
mypy
to do the static type checking for you - If you are on python 3.7 or earlier, you need to manually install
typing_extensions
as well, sinceProtocol
is not part of the coretyping
module in them - Last but not least, using protocols for dataclasses in this way doesn't work right now
更多EAFP启发了这一点实际有效
Something slightly more EAFP-inspired that actually works
from dataclasses import is_dataclass
def dataclass_only(x):
"""Do something that only makes sense with a dataclass.
Raises:
ValueError if something that is not a dataclass is passed.
... more documentation ...
"""
if not is_dataclass(x):
raise ValueError(f"'{x.__class__.__name__}' is not a dataclass!")
...
在这种方法中,由于文档,此代码的维护者或用户仍然非常清楚行为.但缺点是您无法对代码进行静态分析(包括 IDE 的类型提示),现在和以后都不会.
In this approach, the behavior is still very clear to a maintainer or user of this code thanks to the documentation. But the downside is that you don't get a static analysis of your code (including type hints by your IDE), not now and not ever.
这篇关于非特定数据类实例的类型提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!