打字.任何vs对象?

Mar*_*nen 21 python type-hinting python-3.5

使用typing.Anyobject打字相比有什么区别吗?例如:

def get_item(L: list, i: int) -> typing.Any:
    return L[i]
Run Code Online (Sandbox Code Playgroud)

相比:

def get_item(L: list, i: int) -> object:
    return L[i]
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 26

是,有一点不同.虽然在Python 3中,所有对象都是实例object,包括object其本身,但只有Any文件才能被typechecker忽略返回值.

Any类型文档字符串该对象的状态是的一个子类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.
Run Code Online (Sandbox Code Playgroud)

然而,适当的typechecker(一个超越isinstance()检查,并且检查对象如何被实际使用中的功能)可以容易地反对object,其中Any总是接受.

Any类型文档:

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

对比行为Any与行为object.类似地Any,每种类型都是子类型object.但是,与之不同的是Any,反之亦然:对象不是每种其他类型的子类型.

这意味着当值object的类型是,类型检查器将拒绝它上面的几乎所有操作,并将它分配给更专业类型的变量(或使用它作为返回值)是类型错误.

并从mypy文档部分Any对象:

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

object可以给一个更具体的类型,而Any实际上意味着任何事情都会发生和类型检查任何使用对象的脱离(即使你后来这样一个对象分配给一个名字 typechecked).

你已经通过接受将你的功能画成了一个未打字的角落list,这与角色完全相同List[Any].类型检查器在那里脱离并且返回值不再重要,但由于您的函数接受包含Any对象的列表,因此正确的返回值将在Any此处.

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

from typing import TypeVar, List

T = TypeVar('T')

def get_item(L: List[T], i: int) -> T:
    return L[i]
Run Code Online (Sandbox Code Playgroud)


Mic*_*x2a 7

Any并且object在表面上相似,但实际上在意义上完全相反.

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))   
Run Code Online (Sandbox Code Playgroud)

相比之下,Any是一个逃生舱,意味着允许您将动态和静态类型的代码混合在一起.Any是限制性最小的类型 - 对类型值允许任何可能的方法或操作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))
Run Code Online (Sandbox Code Playgroud)

你通常应该Any只尝试使用......

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

相比之下,object用于您希望以类型安全的方式指示值必须与任何可能存在的对象完全一致的情况.

我的建议是避免使用,Any除非没有替代方案.Any是一种让步 - 一种让我们真正宁愿生活在一个类型安全的世界中的动力机制.

有关更多信息,请参阅:


对于您的特定示例,我将使用TypeVars,而不是对象或Any.你想要做的是表明你想要返回列表中包含的任何类型.如果列表将始终包含相同的类型(通常是这种情况),您可能希望:

from typing import List, TypeVar

T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
    return L[i]
Run Code Online (Sandbox Code Playgroud)

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