Y a-t-il une différence entre l'utilisation de typing.Any
par opposition à object
en tapant? Par exemple:
def get_item(L: list, i: int) -> typing.Any:
return L[i]
Par rapport à:
def get_item(L: list, i: int) -> object:
return L[i]
Oui, il y a une différence. Bien que dans Python 3, tous les objets sont des instances de object
, y compris object
lui-même, seuls Any
indiquent que la valeur de retour doit être ignorée par le vérificateur.
La docstring de type Any
indique que l'objet est une sous-classe de Any
et vice-versa:
>>> 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.
Cependant, un vérificateur de type approprié (qui va au-delà de isinstance()
vérifie, et qui inspecte comment l'objet est réellement utilisé dans la fonction) peut facilement s'opposer à object
où Any
est toujours accepté.
Depuis la documentation de type Any
:
Notez qu'aucun contrôle de type n'est effectué lors de l'attribution d'une valeur de type
Any
à un type plus précis.
et
Comparez le comportement de
Any
avec le comportement deobject
. Similaire àAny
, chaque type est un sous-type deobject
. Cependant, contrairement àAny
, l'inverse n'est pas vrai: l'objet n'est pas un sous-type de tous les autres types.Cela signifie que lorsque le type d'une valeur est
object
, un vérificateur de type rejettera presque toutes les opérations sur celle-ci, et l'assigner à une variable (ou l'utiliser comme valeur de retour) d'un type plus spécialisé est un type Erreur.
et de la section de documentation de mypy N'importe quel objet vs :
Le type
object
est un autre type qui peut avoir une instance de type arbitraire comme valeur. Contrairement àAny
,object
est un type statique ordinaire (il est similaire àObject
en Java), et seules les opérations valides pour tous les types sont acceptées pour les valeurs d'objet.
object
peut être cast vers un type plus spécifique, tandis que Any
signifie vraiment tout va et un vérificateur de type se désengage de toute utilisation de l'objet (même si vous attribuez ultérieurement un tel objet à un nom qui est vérifié).
Vous avez déjà peint votre fonction dans un coin non tapé en acceptant list
, ce qui revient à être la même chose que List[Any]
. Le vérificateur de type s'y est désengagé et la valeur de retour n'a plus d'importance, mais puisque votre fonction accepte une liste contenant des objets Any
, la valeur de retour appropriée serait Any
ici.
Pour participer correctement au code vérifié par type, vous devez marquer votre entrée comme List[T]
(Un conteneur typé de façon générique) pour qu'un vérificateur de type puisse ensuite se soucier de la valeur de retour. Dans votre cas, ce serait T
puisque vous récupérez une valeur dans la liste. Créez T
à partir d'un TypeVar
:
from typing import TypeVar, List
T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
return L[i]
Any
et object
sont superficiellement similaires, mais en fait ils sont entièrement opposés dans leur signification.
object
est la racine de la hiérarchie des métaclasses de Python. Chaque classe hérite de object
. Cela signifie que object
est dans un certain sens le type le plus restrictif que vous pouvez donner. Si vous avez une valeur de type object
, les seules méthodes que vous êtes autorisé à appeler sont celles qui font partie de chaque objet. Par exemple:
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))
En revanche, Any
est une hachure d'échappement destinée à vous permettre de mélanger du code typé dynamiquement et statiquement. Any
est le type le moins restrictif - toute méthode ou opération possible est autorisée sur une valeur de type Any
. Par exemple:
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))
Vous devez généralement essayer et utiliser Any
uniquement dans les cas où ...
Dict[str, Any]
, Ce qui est un peu mieux que rien.En revanche, utilisez object
pour les cas où vous souhaitez indiquer de façon sûre qu'une valeur DOIT littéralement fonctionner avec tout objet possible existant.
Ma recommandation est d'éviter d'utiliser Any
sauf dans les cas où il n'y a pas d'alternative. Any
est une concession - un mécanisme pour permettre le dynamisme là où nous préférerions vraiment vivre dans un monde sûr.
Pour plus d'informations, voir:
Pour votre exemple particulier, j'utiliserais TypeVars , plutôt que l'objet ou Any. Ce que vous voulez faire, c'est indiquer que vous voulez retourner le type de tout ce qui est contenu dans la liste. Si la liste contiendra toujours le même type (ce qui est généralement le cas), vous voudriez faire:
from typing import List, TypeVar
T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
return L[i]
De cette façon, votre fonction get_item
Renverra le type le plus précis possible.