65

typing.Any使用和object打字有什么区别吗?例如:

def get_item(L: list, i: int) -> typing.Any:
    return L[i]

相比:

def get_item(L: list, i: int) -> object:
    return L[i]
4

2 回答 2

75

是,有一点不同。尽管在 Python 3 中,所有对象都是 的实例object,包括object它自己,但只有Any返回值应该被类型检查器忽略的文档。

Any类型 docstring 声明 object 是一个子类,反之亦然Any

>>> import typing
>>> print(typing.Any.__doc__)
Special type indicating an unconstrained type.

    - Any object is an instance of Any.
    - Any class is a subclass of Any.
    - As a special case, Any and object are subclasses of each other.

然而,一个适当的类型检查器(一个超越isinstance()检查,检查对象在函数中的实际使用方式)可以很容易地反对objectwhereAny总是被接受的。

Any类型文档

Any请注意,将类型的值分配给更精确的类型时,不会执行类型检查。

Any将 的行为与 的行为进行对比object。与 类似Any,每种类型都是 的子类型object。然而,与 不同Any的是,相反的情况并非如此: object 不是所有其他类型的子类型。

这意味着当值的类型为 时object,类型检查器将拒绝对其进行的几乎所有操作,并将其分配给更专业类型的变量(或将其用作返回值)是类型错误。

并来自 mypy 文档部分Any vs. object

该类型object是另一种可以将任意类型的实例作为值的类型。不同于Any,object是一个普通的静态类型(类似于ObjectJava 中的),对象值只接受对所有类型都有效的操作。

object可以转换为更具体的类型,而Any实际上意味着任何事情都会发生,并且类型检查器会脱离对对象的任何使用(即使您稍后将此类对象分配给经过类型检查的名称

您已经通过接受将您的函数绘制成一个未键入的角落list,这归结为与List[Any]. 类型检查器在那里脱离并且返回值不再重要,但是由于您的函数接受包含Any对象的列表,因此正确的返回值将在Any这里。

要正确参与类型检查代码,您需要将输入标记为List[T](一般类型的容器),以便类型检查器能够关心返回值。在您的情况下,这是T因为您正在从列表中检索一个值。T从创建TypeVar

from typing import TypeVar, List

T = TypeVar('T')

def get_item(L: List[T], i: int) -> T:
    return L[i]
于 2016-10-02T12:43:19.963 回答
20

Anyobject表面上相似,但实际上意义完全相反

object是 Python 元类层次结构的。每个类都继承自object. 这意味着从object某种意义上说,这是您可以赋予值的最严格的类型。如果你有一个 type 的值,那么你object唯一被允许调用的方法是每个对象的一部分。例如:

foo = 3  # type: object

# Error, not all objects have a method 'hello'
bar = foo.hello()   

# OK, all objects have a __str__ method
print(str(foo))   

相反,Any它是一个逃生舱口,旨在让您将动态和静态类型的代码混合在一起。Any是限制最少的类型 - 任何可能的方法或操作都允许对 type 的值Any。例如:

from typing import Any
foo = 3  # type: Any

# OK, foo could be any type, and that type might have a 'hello' method
# Since we have no idea what hello() is, `bar` will also have a type of Any
bar = foo.hello()

# Ok, for similar reasons
print(str(foo))

您通常应该尝试Any仅在以下情况下使用...

  1. 作为将动态和静态类型代码混合在一起的一种方式。例如,如果您有许多动态和复杂的函数,并且没有时间对所有这些函数进行完全静态类型化,那么您可以满足于只给它们一个返回类型 Any 来名义上将它们带入类型检查的工作中。(或者换句话说,Any 是一个有用的工具,可以帮助将未经类型检查的代码库分阶段迁移到有类型的代码库)。
  2. 作为为难以键入的表达式赋予类型的一种方式。例如,Python 的类型注释目前不支持递归类型,这使得键入任意 JSON dicts 之类的东西变得困难。作为一种临时措施,您可能希望给您的 JSON dicts 一种类型Dict[str, Any],这比没有好一点。

相反,object用于您希望以类型安全的方式指示值必须从字面上与存在的任何可能对象一起使用的情况。

我的建议是避免使用,Any除非在别无选择的情况下。Any是一种让步——一种允许我们真正宁愿生活在类型安全世界中的活力的机制。

有关更多信息,请参阅:


对于您的特定示例,我将使用TypeVars,而不是 object 或 Any。您要做的是表明您要返回列表中包含的任何内容的类型。如果列表将始终包含相同的类型(通常是这种情况),您会想要这样做:

from typing import List, TypeVar

T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
    return L[i]

这样,您的get_item函数将尽可能返回最精确的类型。

于 2016-10-02T20:37:09.620 回答