类型提示:给原始数据类型添加别名是一种不好的做法吗? [英] Type hints: Is it a bad practice to alias primitive data types?

查看:24
本文介绍了类型提示:给原始数据类型添加别名是一种不好的做法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Python 文档中输入 &类型提示我们有以下示例:

In Python documentation for typing & type hints we have the below example:

Vector = List[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

Vector 类型别名清楚地表明,类型别名对于简化复杂的类型签名很有用.

Vector type alias clearly shows that type aliases are useful for simplifying complex type signatures.

但是,原始数据类型别名如何?

让我们对比两个函数签名的基本示例:

Let's contrast two basic examples of function signatures:

URL = str    

def process_url(url: URL) -> URL:
    pass

对比

def process_url(url: str) -> str:
    pass

具有类型别名 URL 的原始类型 str 的版本是:

Version with type alias URL for primitive type str is:

  • 自我记录(除其他外,现在我可以跳过记录返回值,因为它应该清楚地是一个网址),
  • 抵抗类型实现更改(我可以稍后将 URL 切换为 Dictnamedtuple,而无需更改函数签名).
  • self-documenting (among others, now I can skip documenting returned value, as it should be clearly an url),
  • resistant to type implementation change (I can switch URL to be Dict or namedtuple later on without changing functions signatures).

问题是我找不到其他人遵循这种做法.我只是担心我无意中滥用类型提示来实现我自己的想法,而不是遵循它们的预期目的.

The problem is I cannot find anyone else following such practice. I am simply afraid that I am unintentionally abusing type hints to implement my own ideas instead of following their intended purpose.

2020-10 年的注意事项

Python 3.9 引入了灵活的函数和变量注释",允许进行如下注释:

Python 3.9 introduces "flexible function and variable annotations", which allows to make annotations like:

def speed_1(distance: "feet", time: "seconds") -> "miles per hour":
    pass

def speed_2(
    distance: Annotated[float, "feet"], time: Annotated[float, "seconds"]
) -> Annotated[float, "miles per hour"]:
    pass

为了文档目的而呈现别名数据类型相当多余!

Which renders aliasing data types for documenting purposes rather redundant!

见:

推荐答案

使用别名来标记值的含义可能会产生误导和危险.如果只有一部分值有效,则应使用 NewType.

Using an alias to mark the meaning of a value can be misleading and dangerous. If only a subset of values are valid, a NewType should be used instead.

回想一下,类型别名的使用将两种类型声明为彼此等效.执行 Alias = Original 将使静态类型检查器将 Alias 视为 完全等效Original 所有情况.当您想简化复杂的类型签名时,这很有用.

Recall that the use of a type alias declares two types to be equivalent to one another. Doing Alias = Original will make the static type checker treat Alias as being exactly equivalent to Original in all cases. This is useful when you want to simplify complex type signatures.

简单的别名有两种作用:别名 URL = str 意味着任何 URL 是一个 str 也意味着 任何 str 都是一个 URL——这通常是不正确的:URL 是一种特殊的 str,没有任何一个可以代替它.别名 URL = str 是一种过于强烈的相等性声明,因为它无法表达这种区别.其实任何不看源码的检查都看不出区别:

Simple aliasing works both ways: the alias URL = str means any URL is a str and also means any str is a URL – which is usually not correct: A URL is a special kind of str and not any can take its place. An alias URL = str is a too strong statement of equality, as it cannot express this distinction. In fact, any inspection that does not look at the source code does not see the distinction:

In [1]: URL = str
In [2]: def foo(bar: URL):
   ...:     pass
   ...:
In [3]: foo?
Signature: foo(bar: str)

考虑在一个模块中为 Celsius = float 设置别名,而在另一个模块中为 Fahrenheit = float 设置别名.这表明将 Celsius 用作 Fahrenheit 是有效的,这是错误的.

Consider that you alias Celsius = float in one module, and Fahrenheit = float in another. This signals that it is valid to use Celsius as Fahrenheit, which is wrong.

除非您的类型do带有分离意义,否则您应该只取一个url: str.名称表示含义,类型表示有效值.这意味着您的类型应该适合分隔有效值和无效值!

Unless your types do cary separative meaning, you should just take a url: str. The name signifies the meaning, the type the valid values. That means that your type should be suitable to separate valid and invalid values!

使用别名缩短你的提示,但使用NewType细化它们.

Use aliases to shorten your hints, but use NewType to refine them.

Vector = List[float]        # alias shortens
URL = NewType("URL", str)   # new type separates

这篇关于类型提示:给原始数据类型添加别名是一种不好的做法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆