输入模块允许将复杂类型签名分配给aliases,然后可以与实际类型互换使用。这似乎有一个问题,即它将类型别名与实际类混淆,即在像这样的定义
中def foo(obj: MyComplexObject):
...
无法判断MyComplexObject
是作为某个类实现的,还是仅仅是类型别名。这对我来说似乎是一个令人遗憾的混淆源,特别是当别名(重新)远离其原始定义时。这是普遍接受还是有某种惯例以某种方式区分类型别名和实际类?
答案 0 :(得分:2)
我认为类型别名和常规类型在设计上是无法区分的:类型别名对于任何类型的别名都是准确的替身。
因此,要使用您的示例,如果MyComplexObject
是实际类或类型别名,它们并不一定重要:它们在运行时和静态类型检查时都表现相同。
因为类型检查器可以为您提供关于您是否以类型安全方式使用obj
的即时反馈,所以很少有机会感到困惑:要么您将使用正确的obj
参数,否则您将获得即时反馈。 (同样,理解PEP 484语义的Pycharm之类的IDE也会理解类型别名,并且会正确地自动完成/标记错误。)
同样值得注意的是,在您特别为其他类别名的情况下,别名和原始类在运行时几乎无法区分:它们都是引用相同底层类型对象的两个变量。 (可以说,实际上没有什么可以混淆的:别名和原始类型都是"同样的东西"。)
因此,很难找到一种区分类型和类型别名的命名约定 - 它实际上并没有真正成为一个问题。
也就是说, 类型别名的隐含约定。例如,人们通常不直接使用别名:类型别名,如Ethan所说,主要用于帮助简化在多个地方重复的较大化合物类型。
这意味着类型别名主要用于否则会有一堆非常难看的类型签名。然后它变成了一个权衡"有点事情:读者确实需要花时间查找别名的定义并将其缓存在脑海中,但一旦他们这样做,阅读其余代码应该更加愉快。
因此,如果您仍然发现类型别名可能会造成混淆,并且除非必要,我们更愿意避免使用它们,这完全没问题:这几乎是其他人所做的事情。唯一的区别归结为当你跨过那个临界点时,不必要的"必要"。
答案 1 :(得分:1)
没有官方惯例区分这两者。
类型别名与其他语言中的typedef非常相似。但是,按惯例,类型别名用于复杂的类型组合,例如Message = Union[str, MyClass1, MyClass2, OtherClass]
,其中多次写出完整联合将是麻烦的。因此,单个名称注释应该是:类型或别名的某些类型组合。您必须转到该名称的定义,以区别对待。