escribiendo.Any vs objeto?

¿Hay alguna diferencia entre usar la escritura? ¿ typing.Any opuesto al object al escribir? Por ejemplo:

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

Comparado con:

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

Sí, hay una diferencia. Aunque en Python 3, todos los objetos son instancias de un object , incluido el object sí, solo el documento debe ignorar el valor de retorno.

La cadena de documentación Any type indica que el objeto es una subclase de Any y viceversa:

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

Sin embargo, un comprobador de tipo adecuado (uno que va más allá de las isinstance() y que inspecciona cómo se utiliza realmente el objeto en la función) puede objetar fácilmente un objeto en el object siempre se acepta Any .

De la documentación de Any tipo :

Observe que no se realiza ninguna comprobación de tipo al asignar un valor de tipo Any a un tipo más preciso.

y

Contraste el comportamiento de Any con el comportamiento del object . Similar a Any , cada tipo es un subtipo de object . Sin embargo, a diferencia de Any , lo contrario no es cierto: el objeto no es un subtipo de ningún otro tipo.

Eso significa que cuando el tipo de un valor es un object , un comprobador de tipos rechazará casi todas las operaciones en él, y asignarlo a una variable (o usarlo como valor de retorno) de un tipo más especializado es un error de tipo.

y de la sección de documentación de mypy Any vs. object :

El object tipo es otro tipo que puede tener una instancia de tipo arbitrario como valor. A diferencia de Any , object es un tipo estático ordinario (es similar a Object en Java), y solo se aceptan las operaciones válidas para todos los tipos para los valores de los objetos.

object se puede convertir a un tipo más específico, mientras que Any realmente significa que todo vale y un verificador de tipos se desactiva de cualquier uso del objeto (incluso si más adelante asigna un objeto a un nombre que se verifica).

Ya pintaste tu función en una esquina sin escribir al aceptar la list , que se reduce a ser lo mismo que List[Any] . El buscador de tipos desactivado allí y el valor de retorno ya no importa, pero como su función acepta una lista que contiene Any objeto, el valor de retorno correcto sería Any aquí.

Para participar adecuadamente en el código de verificación de tipo, debe marcar su entrada como List[T] (un contenedor genérico) para que un verificador de tipos pueda luego preocuparse por el valor de retorno. Lo que en su caso sería T ya que está recuperando un valor de la lista. Crear T desde un TypeVar :

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

Any object y object son superficialmente similares, pero en realidad tienen un significado totalmente opuesto .

object es la raíz de la jerarquía de metaclases de Python. Cada clase individual hereda del object . Eso significa que ese object es, en cierto sentido, el tipo más restrictivo que puede dar valores. Si tiene un valor de tipo object , los únicos métodos a los que se le permite llamar son los que forman parte de cada objeto. Por ejemplo:

 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)) 

Por el contrario, Any es una compuerta de escape destinada a permitirle mezclar código dynamic y estático. Any es el tipo menos restrictivo: cualquier método u operación posible está permitido en un valor de tipo Any . Por ejemplo:

 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)) 

Por lo general, deberías probar y usar Any solo para los casos donde

  1. Como una forma de mezclar código dynamic y estático. Por ejemplo, si tiene muchas funciones dinámicas y complejas, y no tiene tiempo para escribirlas todas de manera estática, podría conformarse con solo darles un tipo de Devolución para que nominalmente las incorporen al trabajo que se verifica. (O para decirlo de otra manera, Any es una herramienta útil para ayudar a migrar un código base sin código a un código base escrito en etapas).
  2. Como una forma de dar un tipo a una expresión que es difícil de escribir. Por ejemplo, las anotaciones de tipo de Python actualmente no son compatibles con los tipos recursivos, lo que dificulta la escritura de elementos como dictados JSON arbitrarios. Como medida temporal, es posible que desee darle a sus dictados JSON un tipo de Dict[str, Any] , que es un poco mejor que nada.

En contraste, use el object para los casos en los que desee indicar de una manera segura que un valor DEBE funcionar literalmente con cualquier objeto posible existente.

Mi recomendación es evitar el uso de Any excepto en los casos en que no haya alternativa. Any es una concesión, un mecanismo para permitir el dinamismo donde realmente preferiríamos vivir en un mundo seguro.

Para más información, ver:


Para su ejemplo particular, usaría TypeVars , en lugar de cualquier objeto o Cualquiera. Lo que desea hacer es indicar que desea devolver el tipo de lo que se encuentra dentro de la lista. Si la lista siempre contendrá el mismo tipo (que suele ser el caso), desearía hacerlo:

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

De esta manera, su función get_item devolverá el tipo más preciso posible.