如何在不注释类型的情况下添加数据类字段?

30

当数据类中有一个字段其类型可以是任何类型时,如何省略注释?

@dataclass
class Favs:
    fav_number: int = 80085
    fav_duck = object()
    fav_word: str = 'potato'

看起来上面的代码并没有真正创建一个fav_duck字段,它只是将其作为普通的类属性。

>>> Favs()
Favs(fav_number=80085, fav_word='potato')
>>> print(*Favs.__dataclass_fields__)
fav_number fav_word
>>> Favs.fav_duck
<object at 0x7fffea519850>

1
使用鸭子类型的dataclasses替代方案:https://www.attrs.org - BlackJack
4个回答

27

数据类装饰器会检查类以查找字段,通过在 __annotations__ 中查找名称来确定字段。 注释的存在使字段成为可能, 因此,您确实需要一个注释。

但是,您可以使用通用注释:

@dataclass
class Favs:
    fav_number: int = 80085
    fav_duck: 'typing.Any' = object()
    fav_word: str = 'potato'

8
根据定义数据类含义的PEP 557dataclass装饰器检查类以查找字段。字段被定义为在__annotations__中标识的任何变量,也就是具有类型注释的变量。这意味着,在dataclass上下文中,“字段”的前提(例如,“如何使用没有类型注释的字段与dataclass”)必须被拒绝。需要注意的是,使用像typing.Any这样的通用类型注释并不等同于具有未注释属性,因为该属性将出现在__annotations__中。最后,辅助函数make_dataclass将在仅提供属性名称的情况下自动使用typing.Any作为类型注释,在PEP中也提到了这一点,并给出了示例。

6

类型提示是Python的可选功能。这也意味着,使用@dataclass不需要您定义类型。

在注释中,您可以写很多东西。如果您不想检查它们,那么它们将不会被检查。以下示例有效:

@dataclass
class ColoredObject:
    color : "" 
    name : ""

@dataclass
class ColoredObject:
    color : ... 
    name : ...

@dataclass
class ColoredObject:
    color : True 
    name : True

@dataclass
class ColoredObject:
    color : object
    name : object

@dataclass
class ColoredObject:
    color : None
    name : None

我在这里列出了很多选项,以便您可以决定是否喜欢其中的某些选项。如何使用代码注释是您的决定。

对于那些习惯于比Python更静态类型语言的人来说,这可能是一种尴尬的风格。看起来像是滥用空字符串或椭圆对象来实现此目的。而且确实如此。但请记住,在编程中,代码可读性也很重要。有趣的是,大多数阅读您代码的人甚至不知道存在椭圆对象,也会直观地理解您写下的...

当然,如果您不想让那些喜欢类型提示的人感到困惑,或者您想使用期望正确类型提示的工具,您必须就此达成一致。

我没有列出使用typing.Any的解决方案。当然,那也是一个好的解决方案。但是,类型是Python的可选功能。这也意味着知道有typing.Any这样的东西是可选的知识。


0
如果您能在文件顶部添加from __future__ import annotations,这将把文件中的所有注释转换为字符串,以便它们被惰性评估;这对于定义不需要在运行时解析的注释非常有用。
例如,使用短而简单的类型注释(_)来表示字段的一种方式:
from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING


# added to silence any IDE warnings (i.e. PyCharm)
if TYPE_CHECKING:
    _ = object


@dataclass
class Favs:
    fav_number: int = 80085
    fav_duck: _ = object()
    fav_word: str = 'potato'


print(Favs())

输出:

Favs(fav_number=80085, fav_duck=<object object at 0x11b754ad0>, fav_word='potato')

如果您不想或无法使用__future__导入(即如果您使用的是Python 3.6或更低版本,或者想要消除IDE警告的“未解决的引用”),您可以始终预先定义类型注释的值:

from dataclasses import dataclass


# or: 
#   = ...
_ = object


@dataclass
class Favs:
    fav_number: int = 80085
    fav_duck: _ = object()
    fav_word: str = 'potato'


print(Favs())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接