El módulo de typing
proporciona una clase base para sugerencias de tipo genérico: la clase typing.Generic
.
Las subclases de Generic
aceptan argumentos de tipo entre corchetes, por ejemplo:
list_of_ints = typing.List[int] str_to_bool_dict = typing.Dict[str, bool]
Mi pregunta es, ¿cómo puedo acceder a estos argumentos de tipo?
Es decir, dado str_to_bool_dict
como entrada, ¿cómo puedo obtener str
y bool
como salida?
Básicamente estoy buscando una función tal que
>>> magic_function(str_to_bool_dict) (, )
A partir de Python 3.6. hay un campo público __args__
y ( __parameters__
). Por ejemplo:
print( typing.List[int].__args__ )
Esto contiene los parámetros generics (es decir, int
), mientras que __parameters__
contiene el genérico en sí (es decir, ~T
).
Utilice typing_inspect.getargs
typing
sigue PEP8 . Tanto PEP8 como la typing
son coautoras de Guido van Rossum. Un subrayado doble inicial y final se define como “objetos o atributos” mágicos “que viven en espacios de nombres controlados por el usuario “ .
Los dunders también se comentan en línea; desde el repository oficial para escribir podemos ver: * ” __args__
es una tupla de todos los argumentos utilizados en las suscripciones, por ejemplo, Dict[T, int].__args__ == (T, int)
“.
Sin embargo, los autores también notan : * “El módulo de escritura tiene un estado provisional, por lo que no está cubierto por los altos estándares de compatibilidad con versiones anteriores (aunque intentamos mantenerlo tanto como sea posible), esto es especialmente cierto para (aún sin documentar) dunder atributos como __union_params__
. Si desea trabajar con tipos de escritura en el contexto de tiempo de ejecución, entonces puede estar interesado en el proyecto typing_inspect
(parte del cual puede terminar escribiendo más adelante).
En general, todo lo que haga con la typing
tendrá que mantenerse actualizado por el momento. Si necesita reenviar cambios compatibles, le recomendaría que escriba sus propias clases de anotación.
Parece que este método interno hará el truco.
typing.List[int]._subs_tree()
que devuelve la tupla:
(typing.List, )
Pero esta es una API privada, probablemente hay una mejor respuesta.
Por lo que sé, no hay una respuesta feliz aquí.
Lo que viene a la mente es el atributo __args__
indocumentado que almacena esta información:
list_of_ints.__args__ >>>(,) str_to_bool_dict.__args__ >>>( , )
pero no se menciona en la documentación del módulo de typing
.
Vale la pena señalar que estaba muy cerca de ser mencionado en la documentación, sin embargo:
Probablemente también deberíamos discutir si necesitamos documentar todos los argumentos de palabras clave para
GenericMeta.__new__
. Haytvars
,args
,origin
,extra
yorig_bases
. Creo que podríamos decir algo sobre los tres primeros (corresponden a__parameters__
,__args__
, y__origin__
y estos son utilizados por la mayoría de las cosas al escribir).
Pero no lo consiguió del todo .
GenericMeta
a__all__
y agregué cadenas de documentación aGenericMeta
yGenericMeta.__new__
luego de la discusión en el tema. Decidí no describir a__origin__
y amigos en cadenas de documentos. En su lugar, acabo de agregar un comentario en el lugar donde se usan por primera vez.
A partir de ahí, todavía tienes tres opciones que no se excluyen mutuamente:
espere a que el módulo de typing
scope su plena madurez y espere que estas características se documenten pronto
únase a la lista de correo de ideas de Python y vea si se puede obtener suficiente apoyo para hacer que estos elementos internos sean públicos / parte de la API
Mientras tanto, trabaje con las partes internas indocumentadas, apostando a que no habrá cambios en estos o que los cambios serán menores.
Tenga en cuenta que el tercer punto difícilmente se puede evitar ya que incluso la API puede estar sujeta a cambios :
El módulo de escritura se ha incluido en la biblioteca estándar de forma provisional. Se pueden agregar nuevas características y la API puede cambiar incluso entre versiones menores si los desarrolladores centrales lo consideran necesario .
Usa el .__args__
en tus construcciones. Así que la función mágica que necesitas es algo como:
get_type_args = lambda genrc_type: getattr(genrc_type, '__args__')
Mi pregunta es, ¿cómo puedo acceder a estos argumentos de tipo?
En situaciones como estas, ¿cómo puedo acceder …
Usa las poderosas características de introspección de Python.
Incluso como progtwigdor no profesional, sé que estoy tratando de inspeccionar cosas y dir
es una función que es como IDE en el terminal. Así que después
>>> import typing >>> str_to_bool_dict = typing.Dict[str, bool]
Quiero ver si hay algo que haga la magia que quieres.
>>> methods = dir(str_to_bool_dict) >>> methods ['__abstractmethods__', '__args__', .....]
Veo demasiada información, para ver si estoy en lo correcto verifico
>>> len(methods) 53 >>> len(dir(dict)) 39
Ahora encontremos los métodos que fueron diseñados específicamente para tipos generics
>>> set(methods).difference(set(dir(dict))) {'__slots__', '__parameters__', '_abc_negative_cache_version', '__extra__', '_abc_cache', '__args__', '_abc_negative_cache', '__origin__', '__abstractmethods__', '__module__', '__next_in_mro__', '_abc_registry', '__dict__', '__weakref__'}
entre estos, __parameters__
, __extra__
, __args__
y __origin__
suenan útiles. __extra__
y __origin__
no funcionarán sin uno mismo, por lo que nos quedamos con __parameters__
y __args__
.
>>> str_to_bool_dict.__args__ (, )
De ahí la respuesta.
La introspección permite que las declaraciones de afirmación de py.test
hagan que los marcos de prueba derivados de JUnit parezcan obsoletos. Incluso los lenguajes como JavaScript / Elm / Clojure no tienen una aplicación directa como Python. La convención de nomenclatura de Python le permite descubrir el idioma sin leer realmente (documentando en algunos casos como estos) las documentaciones.
Así que busque utilizando la introspección y lea la documentación / listas de correo para confirmar sus hallazgos.
PS a OP: este método también responde a su pregunta ¿Cuál es la forma correcta de verificar si un objeto está escribiendo? ¿Genérico? use discovery si no puede comprometerse con la lista de correo o si es un desarrollador ocupado, esa es la forma de hacerlo en Python.