类型提示中的可选联合

33
在类型提示系统中,Optional[T] 被认为等同于 Union[T, None]
对于多个类型参数是否也适用呢?例如,Optional[T,U] 是否可以拆分为 Union[T,U,None],还是需要写成 Optional[Union[T,U]]

似乎 Optional[int, str] 会导致 TypeError。然而,Union[None, int, str] 占用的空间比更易读的 Optional[Union[int, str]] 少。 - GeeTransit
2
这里最重要的一点是,如果你有一个函数,其参数可以是多种类型之一或者为空,那么你应该更加明确这个类型的含义。Username = typing.TypeVar('Username', str); UserId = typing.TypeVar('UserId', int); UserIdentifier = typing.Union[Username, UserId]; Optional[UserIdentifier] 现在就有了明确的含义。 - Adam Smith
@AdamSmith 我有一个试验性的用例需要对数据库条目进行变异。我想为数据类中的任何字段指定三种可能的状态,其中数据类表示对数据库条目的变异。假设字段t是类型T。要么tT,因此存在并且需要更新,要么tNone,应将其忽略,要么t是某个标记类type(Removal),需要删除。我的字段看起来像foo: Optional[Union[str, Removal]]。有没有更清晰的方法来重用这种键入格式?以某种方式得到说foo: Modifiable[str]? - flakes
1
@flakes 当然可以!类型只是像其他对象一样的东西。Modifiable = Optional[Union[str, Removal]] 是有效的。 - Adam Smith
1
如果您想要明确指定可修改的类型(例如 Modifiable[str]Modifiable[int]),那么可以按照 Python 内部定义 UnionOptional 的方式进行定义。请参见 https://gitlab.com/snippets/1836727。 - Adam Smith
@AdamSmith 太棒了!谢谢你! - flakes
1个回答

23
您可以将typing库视为声明特定类型的规范。如果某些内容在规范中未定义,则最好假设它是未定义的行为。
然而,在Python和类型注释方面,我们有一种静态类型检查器mypy。因此,为了回答您的问题或仅编程检查类型,我们可以使用它并查看它是否显示任何警告。
以下是一个示例:
$ cat check_optional.py 
import typing
def fn(x: typing.Optional[int, str]):
    pass
$ mypy check_optional.py 
check_optional.py:3: error: Optional[...] must have exactly one type argument

所以,从mypy的角度来看,即使在typing库中声明它没有问题,Optional[T, U]也是不可能的。
此外,从“函数式编程”角度来看,OptionalUnion都是两个独立但众所周知且定义良好的monads。两个monad(Union[T, U, None])的组合是另一个monad,但是其行为与Optional不同,因此不应该以此命名。换句话说,Union[T, U, None]等同于(=相同于)Optional[Union[T, U]],但与一般的Optional[X]不同。

谢谢你的mypy教程,我会在将来使用它!在最后的评论中,您是不是想写Union[T, U, None]和可选项不同? - flakes
3
很高兴听到这个消息!在最后一段中,我的意思是 Union[T, U, None]Optional[Union[T, U]] 是同构的(即相同),但不同于一般的 Optional[X] - Vladimir
PEP 604 明确指出 None | x == Union[None, x] == Optional[x] - cowlinator
确实如此。但并没有解释问题。 - Chiffa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接