web-dev-qa-db-fra.com

tout objet vs?

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]
27
Markus Meskanen

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 à objectAny 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 de object. Similaire à Any, chaque type est un sous-type de object. 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]
29
Martijn Pieters

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ù ...

  1. Comme moyen de mélanger du code dynamique et du code typé statiquement. Par exemple, si vous avez de nombreuses fonctions dynamiques et complexes, et que vous n'avez pas le temps de les saisir entièrement de manière statique, vous pouvez vous contenter de leur donner un type de retour Any pour les intégrer nominalement dans le travail vérifié. (Ou pour le dire autrement, Any est un outil utile pour aider à migrer une base de code non vérifiée vers une base de code typée par étapes).
  2. Pour donner un type à une expression difficile à taper. Par exemple, les annotations de type de Python ne prennent actuellement pas en charge les types récursifs, ce qui rend difficile la saisie de choses comme les dictons JSON arbitraires. À titre temporaire, vous souhaiterez peut-être donner à vos scénarios JSON un type de 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.

8
Michael0x2a