这个怎么做最好呢?
PEP 484在这种情况下提供了一个明确的选项。
类型别名是通过简单的变量赋值定义的:
(...)
类型别名可以像注释中的类型提示一样复杂 - 任何在类型提示中被接受的东西都可以在类型别名中被接受。
应用到你的例子中,这意味着(Mypy确认为正确)。
from dataclasses import dataclass
Your_Type = set[tuple[str, float, bool]]
@dataclass
class MyDataClass:
force: Your_Type
def do_something(force: Your_Type):
print(force)
上述是使用 Python 3.9 或更新版本编写的
通用别名类型。由于
typing.Set和
typing.Tuple已被弃用,因此语法更加简洁和现代化。
现在,完全理解这个问题涉及到
Python数据模型,可能比看起来更加复杂:
3.1. 对象、值和类型
每个对象都有一个身份、一种类型和一个值。
你第一次尝试使用 Type
会得到令人惊讶的结果。
>>> type(MyDataClass.force)
AttributeError: type object 'MyDataClass' has no attribute 'force'
这是因为内置函数
type
返回一个类型(它本身也是一个对象),但
MyDataClass
是“一个类”(一个声明),而“类属性”
force
在类上而不是类型对象上,
type()
在类型对象上查找。仔细观察数据模型中的区别:
类
这些对象通常充当它们自己新实例的工厂
类实例
任意类的实例
如果您检查实例的类型,则会得到以下结果。
>>> init_values: set = {(True, "the_str", 1.2)}
>>> a_var = MyDataClass(init_values)
>>> type(a_var)
<class '__main__.MyDataClass'>
>>> type(a_var.force)
<class 'set'>
现在,让我们通过将
type()
应用于类声明对象上的
__anotations__
来恢复
force
的类型对象(而不是类型提示)(这里我们看到先前提到的
通用别名类型)。 (在这里,我们确实检查了类属性
force
上的类型对象。)
>>> type(MyDataClass.__annotations__['force'])
<class 'typing._GenericAlias'>
或者我们可以检查类实例的注释,并像我们通常看到的那样恢复类型提示。
>>> init_values: set = {(True, "the_str", 1.2)}
>>> a_var = MyDataClass(init_values)
>>> a_var.__annotations__
{'force': set[tuple[str, float, bool]]}
我不得不在dataclass和函数签名中写相同的类型注释 -
对于元组注释往往变成长文字,这证明了为简洁起见创建一个目的变量。但是一般来说,显式签名更加描述性,这也是大多数API所采用的方式。
typing模块的基本构建块包括:
Tuple,通过列出元素类型使用,例如Tuple[int, int, str]。空元组可以被定义为Tuple[()]。可以使用一个类型和省略号表示任意长度的同构元组,例如Tuple[int, ...]。(这里的省略号是语法的一部分,是一个字面上的省略号。)
GoodName = Set[Tuple[str, float, bool]]
,并重复使用它,GoodName
。 - juanpa.arrivillaga