非特定数据类实例的类型提示 [英] type hint for an instance of a non specific dataclass

查看:67
本文介绍了非特定数据类实例的类型提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数可以接受任何 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, since Protocol is not part of the core typing 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆