【问题标题】:Convention to distinguish type aliases from actual classes?区分类型别名和实际类的约定?
【发布时间】:2018-10-16 09:33:29
【问题描述】:

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

def foo(obj: MyComplexObject):
    ...

无法判断MyComplexObject 是在某处实现为类还是只是类型别名。对我来说,这似乎是一个令人遗憾的混淆来源,尤其是当别名(重新)使用远离其原始定义时。这是否被普遍接受,或者是否有某种约定可以以某种方式将类型别名与实际类区分开来?

【问题讨论】:

    标签: python type-hinting mypy


    【解决方案1】:

    没有区分这两者的官方惯例。

    类型别名与其他语言中的 typedef 非常相似。但是,按照惯例,类型别名用于复杂的类型组合,例如Message = Union[str, MyClass1, MyClass2, OtherClass],在这种情况下多次写出完整的联合会很麻烦。因此,单个名称注释应该是:一种类型,或者具有别名的类型的某种组合。您必须查看该名称的定义才能将它们区分开来。

    【讨论】:

    • 嗯,这真是令人不快的情况。我几乎倾向于考虑类似匈牙利符号的别名声明 (MyComplexObject_t),这比不断怀疑我是否定义过特定的类要少一些烦人。
    • 类型别名,像所有抽象一样,只有在正确完成的情况下才有效。他们将复杂的事物隐藏在更简单的事物中。从根本上说,您正在尝试打破抽象障碍,而且可能不应该这样做。相反,给你的别名赋予语义上有意义的名字,让它们决定理解类型。
    【解决方案2】:

    我相信类型别名和常规类型在设计上是无法区分的:类型别名旨在准确替代它们所使用的任何类型。

    因此,以您的示例为例,MyComplexObject 是实际类还是类型别名并不一定重要:它们在运行时和静态类型检查时的行为相同。

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

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

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


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

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

    因此,如果您仍然发现类型别名可能令人困惑,并且除非必要,否则宁愿避免使用它们,那很好:反正其他人几乎都是这样做的。唯一的区别归结为当你从“不必要”到“必要”的临界点时。

    【讨论】:

      猜你喜欢
      • 2014-09-08
      • 2012-12-09
      • 2022-11-15
      • 2019-11-24
      • 2020-06-13
      • 1970-01-01
      • 2020-04-06
      • 2021-08-11
      • 1970-01-01
      相关资源
      最近更新 更多