联合类型实际上存在于python中吗?

Lan*_*ana 11 python types dynamic-typing unions

由于python是动态类型的,当然我们可以这样做:

def f(x):
    return 2 if x else "s"
Run Code Online (Sandbox Code Playgroud)

但实际上是否打算使用python的方式?或换句话说,联盟类型是否存在于他们在球拍中的意义上?或者我们只使用它们:

def f(x):
    if x:
        return "x"
Run Code Online (Sandbox Code Playgroud)

我们需要的唯一"联盟"是什么?

MAC*_*rha 32

注意:正如其他人提到的,Python 类型提示(默认情况下)对运行时行为没有任何影响,它用于静态分析等。

从 Python 3.10 开始,您可以|对联合类型使用分隔符。以Python 3.10 新增功能中的示例为例:

def square(number: int | float) -> int | float:
    return number ** 2

# Instead of 
def square(number: Union[int, float]) -> Union[int, float]:
    return number ** 2
Run Code Online (Sandbox Code Playgroud)

另外,如果您使用的是 Python 3.7+,则可以通过使用该__future__包来获得该功能,但有一些限制:

from __future__ import annotations

# Works in Python 3.7+
def square(number: int | float) -> int | float:
    return number ** 2

# Works only in Python 3.10+
isinstance(3.10, int | float)
numeric = int | float
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅联合类型文档PEP 604


Mar*_*ers 21

当你有一个静态类型语言时,才需要联盟打字,因为你需要声明一个对象可以返回多个类型中的一种(在你的情况下,int或者str,或者在其他的例子strNoneType).

Python 仅处理对象,因此甚至不需要考虑"联合类型".Python函数返回它们返回的内容,如果程序员想要为不同的结果返回不同的类型,那么这就是他们的选择.那么选择是一种架构选择,并且对Python解释器没有任何影响(所以这里没有"基准").

Python 3.5确实引入了用于创建可选类型提示的标准,该标准包括Union[...]Optional[...]注释.

  • @MartijnPieters:**Python 中存在运行时类型检查器。**我知道这些事情,因为[我创作了其中之一](https://github.com/beartype/beartype)。`typing.Union` 绝对是一个运行时的东西,可以在运行时理解、内省和推理。事实上,运行时类型检查器比静态类型检查器具有深远的优势:也就是说,它们说谎(即发出误报和误报)*很多*少。运行时类型检查器消除了对“# type:ignore”垃圾邮件的需要,同时增加了对类型检查的信心和信任。这些都是好事情。 (4认同)
  • 现在是 2022 年,在 Python 3.10+ 中,我们可以使用 `|` 来表示 Union 运算符。https://docs.python.org/3.10/whatsnew/3.10.html#pep-604-new-type-union-operator (3认同)
  • 谢谢你!我知道 python 不是静态类型的。但我想知道,在实践中,是否有必要有一个函数根据参数返回多种类型,或者在 python 中是否总是有办法解决它? (2认同)
  • @Lana:再一次,它是关于函数返回的软件架构选择.保持一致并限制返回的内容是一种很好的做法,但"绕过它"只是使用良好的软件工程实践.例如,如果您的函数可以返回"True,False,None或整数",则需要重新考虑函数设计. (2认同)
  • @joel:Python 类型提示**是静态类型**,已添加到 Python 中。`typing.Union` 不是运行时类型。 (2认同)

Saj*_*uuk 10

类型本身不存在,因为Python只是一种动态类型语言,但是,在较新的Python版本中,Union Type是Type Hinting的一个选项,

from typing import Union,TypeVar

T = TypeVar('T')
def f(x: T) -> Union[str, None]:
    if x:
        return "x"
Run Code Online (Sandbox Code Playgroud)

您可以使用它来注释代码,从而启用IDE /编辑器级语法检查.

  • 你能解释一下 T = TypeVar('T') (2认同)
  • @AlenPaulVarghese `T = TypeVar('T')` 生成一个命名泛型。此答案中提供的方法将接受任何内容作为输入,如果提供的内容不是“None”,则将返回字符串“x”。在这里使用命名泛型是完全没有必要的,但我确实建议研究它们,因为它们允许创建非常有用的模板函数。 (2认同)

Mat*_*haq 7

这里有几个选项可以处理在 Python 中需要标记的 union/sum 类型的用例:

  • 枚举 + 元组

    from enum import Enum
    Token = Enum('Token', ['Number', 'Operator', 'Identifier', 'Space', 'Expression'])
    
    (Token.Number, 42)                            # int
    (Token.Operator, '+')                         # str
    (Token.Identifier, 'foo')                     # str
    (Token.Space, )                               # void
    (Token.Expression, ('lambda', 'x', 'x+x'))    # tuple[str]
    
    Run Code Online (Sandbox Code Playgroud)

    对此的轻微变化使用专用SumType类而不是元组:

    from dataclasses import dataclass
    from typing import Any
    
    @dataclass
    class SumType:
        enum: Enum
        data: Any
    
    SumType(Token.Number, 42)
    
    Run Code Online (Sandbox Code Playgroud)
  • isinstance

    if isinstance(data, int):
        ...
    if isinstance(data, str):
        ...
    
    Run Code Online (Sandbox Code Playgroud)

    或者结合上面的“枚举”想法:

    token = SumType(Token.Number, 42)
    
    if token.enum == Token.Number:
        ...
    
    Run Code Online (Sandbox Code Playgroud)
  • sumtypes模块

当然,这些方法都有其各种缺点。


小智 5

先前的答案未解决的一个用例是从预先存在的类型构建联合类型,并且具有isinstance()预先存在的类型的任何实例都是联合类型的实例。

Python 中通过抽象基类支持这一点。例如:

>>> import abc
>>> class IntOrString(abc.ABC): pass
... 
>>> IntOrString.register(int)
<class 'int'>
>>> IntOrString.register(str)
<class 'str'>
Run Code Online (Sandbox Code Playgroud)

现在intstr可以被视为 的子类IntOrString

>>> issubclass(int, IntOrString)
True
>>> isinstance(42, IntOrString)
True
>>> isinstance("answer", IntOrString)
True
Run Code Online (Sandbox Code Playgroud)