区分类型别名和实际类的约定?

gmo*_*lau 5 python type-hinting mypy

类型模块允许将复杂类型签名分配给别名,然后可以与实际类型互换使用。这似乎有一个问题,它将类型别名与实际的类混淆,即在这样的定义中

def foo(obj: MyComplexObject):
    ...
Run Code Online (Sandbox Code Playgroud)

无法判断是MyComplexObject在某个地方作为类实现还是只是类型别名。对我来说,这似乎是一个不幸的混乱来源,特别是当(重新)使用别名远离其原始定义时。这是普遍接受的还是有一个约定以某种方式区分类型别名和实际的类?

Mic*_*x2a 2

我相信类型别名和常规类型在设计上是无法区分的:类型别名意味着它们所别名的任何类型的精确替代。

因此,要使用您的示例,是否是实际的类或类型别名并不一定重要MyComplexObject:它们在运行时和静态类型检查时的行为都是等效的。

而且由于类型检查器可以立即反馈您是否以obj类型安全的方式使用,因此您很少会感到困惑:要么obj正确使用参数,要么立即得到反馈。(类似地,Pycharm 等理解 PEP 484 语义的 IDE 也将理解类型别名,并正确地自动完成/标记错误。)

还值得注意的是,在您专门为其他类添加别名的情况下,别名和原始类在运行时实际上无法区分:它们都是引用相同基础类型对象的变量。(因此可以说,实际上没有什么可混淆的:别名和原始类型都是“同一件事”。)

因此,几乎没有动力去寻找一种命名约定来区分类型和类型别名——这在实践中并不是真正的问题。


也就是说,对于何时使用类型别名一些隐式约定。例如,人们通常不会直接为类添加别名:正如 Ethan 所说,类型别名主要用于帮助简化在多个地方重复的较大复合类型。

这意味着类型别名主要在您拥有一堆非常丑陋的类型签名时使用。然后它就变成了一种“权衡”之类的事情:读者确实需要花时间查找别名的定义并将其缓存在他们的头脑中,但是一旦他们这样做了,阅读其余的代码应该会更加愉快。

因此,如果您仍然发现类型别名可能令人困惑,并且除非必要,否则宁愿避免使用它们,那完全没问题:这就是几乎其他人所做的事情。唯一的区别在于何时从“不必要”跨越到“必要”的临界点。