Есть ли разница между использованием 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]
Есть ли разница между использованием 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]
Да, есть разница. Хотя в Python 3 все объекты являются экземплярами object
, включая сам object
, только Any
документы, возвращаемые значения которых должны игнорироваться проверкой типов.
Строка документации типа 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.
Тем не менее, надлежащий проверщик типов (который выходит за пределы isinstance()
и который проверяет, как объект фактически используется в функции) может легко возражать против object
где Any
всегда принимается.
Обратите внимание, что при назначении значения типа
Any
более точному типу проверка типов не выполняется.
а также
Сравните поведение
Any
с поведениемobject
. ПодобноAny
, каждый тип является подтипомobject
. Однако, в отличие отAny
, обратное неверно: объект не является подтипом любого другого типа.Это означает, что когда типом значения является
object
, средство проверки типов отклонит почти все операции над ним, и присвоение его переменной (или использование ее в качестве возвращаемого значения) более специализированного типа является ошибкой типа.
и из раздела документации mypy Любой против объекта:
Тип
object
является другим типом, который может иметь экземпляр произвольного типа в качестве значения. В отличие отAny
,object
- это обычный статический тип (он похож наObject
в Java), и только значения, допустимые для всех типов, принимаются для значений объекта.
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]
Any
и object
поверхностно схожи, но на самом деле совершенно противоположны по смыслу.
object
- это корень иерархии метакласса Python. Каждый класс наследует от object
. Это означает, что object
в определенном смысле является самым ограничивающим типом, который вы можете дать значениям. Если у вас есть значение типа 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
является наименее ограничивающим типом - разрешен любой возможный метод или операция при значении типа 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
только для случаев, когда...
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]
Таким образом, ваша функция get_item
вернет наиболее точный тип, насколько это возможно.