The typing module allows assigning complex type signatures to aliases, which can then be used interchangeably with the actual type. This seems to have the problem that it confuses type aliases with actual classes, i.e. in a definition like this
def foo(obj: MyComplexObject): ...
there is no way to tell if
MyComplexObject is implemented as a class somewhere or is just a type alias. This seems to be an unfortunate source of confusion to me, especially when the alias is (re)used far from its original definition. Is that generally accepted or is there a convention to somehow distinguish type aliases from actual classes?
I believe type aliases and regular types are indistinguishable by design: type aliases are meant to be exact stand-ins for whatever type they're aliasing.
So, to use your example, it doesn't necessarily matter if
MyComplexObject is an actual class or a type alias: they both behave equivalently at runtime and static typecheck time.
And because the type checker can give you immediate feedback on whether or not you're using
obj in a type-safe way, there are minimal opportunities to get confused: either you'll use the
obj parameter correctly or you'll get immediate feedback otherwise. (And similarly, IDEs such as Pycharm that understand PEP 484 semantics will also understand type aliases and will correctly auto-complete/flag mistakes.)
並且因為類型檢查器可以為您提供關於您是否以類型安全方式使用obj的即時反饋,所以很少有機會混淆:要么您將正確使用obj參數,要么您將獲得即時反饋除此以外。 (同樣地,理解PEP 484語義的諸如Pycharm之類的IDE也將理解類型別名並且將正確地自動完成/標記錯誤。)
It's also worth noting that in the case where you specifically alias other classes, the alias and the original class are literally indistinguishable at runtime: they're both variables that refer to the same underlying type object. (So arguably, there's nothing to actually be confused about: both the alias and the original type are the "same thing".)
Consequently, there's been very little incentive to find a naming convention for distinguishing between types and type aliases -- it doesn't really end up being an issue in practice.
因此,很難找到一種區分類型和類型別名的命名約定 - 它實際上並不是真正的問題。
That said, there are some implicit conventions for when to use type aliases. For example, people usually don't alias classes directly: type aliases, as Ethan said, are mainly meant to be used to help simplify larger compound types that are repeated in multiple places.
This means that type aliases are mainly used when you would otherwise have a bunch of really ugly type signatures. It then becomes a "tradeoff" sort of thing: the reader does need to spend time looking up the definition of an alias and cache it in their head, but once they do, reading the rest of the code ought to be much more pleasant.
So if you still find type aliases potentially confusing and prefer to avoid using them unless necessary, that's perfectly fine: that's what pretty much everybody else does anyways. The only difference comes down to when you cross that tipping point from "unnecessary" to "necessary".
There is no official convention for distinguishing the two.
Type aliases are very similar to typedefs in other languages. However, by convention type aliases are used for complex combinations of types, such as
Message = Union[str, MyClass1, MyClass2, OtherClass], where writing out the full union multiple times would be cumbersome. So a single name annotation should either be: a type, or some combination of types that are aliased. You must go to the definition of that name to tell them apart.
類型別名與其他語言中的typedef非常相似。但是,按慣例,類型別名用於復雜的類型組合,例如Message = Union [str,MyClass1,MyClass2,OtherClass],其中多次寫出完整聯合將是麻煩的。因此,單個名稱注釋應該是:類型或別名的某些類型組合。您必須轉到該名稱的定義以區分它們。