Le module typing
fournit une classe de base pour les indicateurs de type génériques: Le typing.Generic
class.
Les sous-classes de Generic
acceptent les arguments de type entre crochets, par exemple:
list_of_ints = typing.List[int]
str_to_bool_dict = typing.Dict[str, bool]
Ma question est, comment puis-je accéder à ces arguments de type?
C’est-à-dire que, avec str_to_bool_dict
en entrée, comment puis-je obtenir str
et bool
en sortie?
Fondamentalement, je recherche une fonction telle que
>>> magic_function(str_to_bool_dict)
(<class 'str'>, <class 'bool'>)
À partir de Python 3.6. il existe un champ public __args__
et (__parameters__
) . Par exemple:
print( typing.List[int].__args__ )
Celui-ci contient les paramètres génériques (c'est-à-dire int
), tandis que __parameters__
contient le générique lui-même (c'est-à-dire ~T
).
Utilisez typing_inspect.getargs
typing
suit PEP8 . PEP8 et typing
sont tous deux co-créés par Guido van Rossum. Les traits de soulignement double interligne et fin sont définis comme suit: "objets ou attributs« magiques »qui résident dans les espaces de noms contrôlés par l'utilisateur".
Les dunders sont également commentés en ligne; depuis le référentiel officiel pour en tapant nous pouvons voir: * "__args__
est un tuple de tous les arguments utilisés en subscripting, par exemple, Dict[T, int].__args__ == (T, int)
".
Cependant, le les auteurs notent également }: _: * "Le module de frappe a un statut provisoire, il n'est donc pas couvert par les normes élevées de compatibilité ascendante (bien que nous essayions de le conserver autant que possible). ), ceci est particulièrement vrai pour les attributs dunder (encore non documentés) tels que __union_params__
. Si vous souhaitez travailler avec des types de frappe dans un contexte d'exécution, le projet typing_inspect
vous intéressera peut-être (une partie de celle-ci pourrait être saisie ultérieurement) "
Général, tout ce que vous ferez avec typing
devra être tenu à jour pour le moment. Si vous avez besoin de modifications compatibles en aval, je vous recommande d'écrire vos propres classes d'annotation.
Il semble que cette méthode interne fera l'affaire
typing.List[int]._subs_tree()
qui retourne le tuple:
(typing.List, <class 'int'>)
Mais c'est une API privée, il y a probablement une meilleure réponse.
Pour autant que je sache, il n'y a pas de réponse heureuse ici.
Ce qui me vient à l’esprit est l’attribut __args__
non documenté qui stocke ces informations:
list_of_ints.__args__
>>>(<class 'int'>,)
str_to_bool_dict.__args__
>>>(<class 'str'>, <class 'bool'>)
mais il n'en est pas fait mention dans la documentation du module typing
.
Il est à noter que c'était très proche d'être mentionné dans la documentation cependant:
Nous devrions probablement également déterminer s'il est nécessaire de documenter tous les arguments de mot clé pour
GenericMeta.__new__
. Il existetvars
,args
,Origin
,extra
etorig_bases
. Je pense que nous pourrions dire quelque chose à propos des trois premiers (ils correspondent à__parameters__
,__args__
et__Origin__
et ceux-ci sont utilisés par la plupart des choses en tapant).
Mais cela n’a pas vraiment réussi :
J'ai ajouté
GenericMeta
à__all__
et ajouté docstrings àGenericMeta
etGenericMeta.__new__
à la suite de la discussion dans le numéro . J'ai décidé de ne pas décrire__Origin__
et d'amis dans docstrings. Au lieu de cela, j'ai simplement ajouté un commentaire à l'endroit où ils ont été utilisés pour la première fois.
À partir de là, vous avez encore trois options non mutuellement exclusives:
attendez que le module typing
atteigne sa pleine maturité et espérez que ces fonctionnalités seront bientôt documentées
rejoindre la liste de diffusion idées Python et voir si un support suffisant peut être réuni pour rendre ces internals publics/une partie de l'API
travailler en attendant avec les internes non documentés, en faisant le pari qu'il n'y aura pas de changements à ces derniers ou que les changements seront mineurs.
Notez que le troisième point peut difficilement être évité car même l’API peut être soumis à des modifications :
Le module de dactylographie a été inclus dans la bibliothèque standard à titre provisoire. De nouvelles fonctionnalités peuvent être ajoutées et API peut changer même entre des versions mineures si les développeurs principaux le jugent nécessaire.
Utilisez le .__args__
sur vos constructions. La fonction magique dont vous avez besoin ressemble à quelque chose comme:
get_type_args = lambda genrc_type: getattr(genrc_type, '__args__')
Ma question est, comment puis-je accéder à ces arguments de type?
Dans de telles situations, comment puis-je accéder à ...
Utilisez les puissantes fonctionnalités d’introspection de Python.
Même en tant que programmeur non professionnel, je sais que j’essaie d’inspecter des éléments et que dir
est une fonction qui ressemble à IDE dans le terminal. Donc après
>>> import typing
>>> str_to_bool_dict = typing.Dict[str, bool]
Je veux voir s'il y a quelque chose qui fait la magie que vous voulez afin
>>> methods = dir(str_to_bool_dict)
>>> methods
['__abstractmethods__', '__args__', .....]
Je vois trop d'informations, pour voir si je suis correct, je vérifie
>>> len(methods)
53
>>> len(dir(dict))
39
Maintenant, laissez-nous trouver les méthodes qui ont été conçues spécifiquement pour les types génériques
>>> 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__'}
parmi ceux-ci, __parameters__
, __extra__
, __args__
et __Origin__
semblent utiles. __extra__
et __Origin__
ne fonctionneront pas sans moi, il nous reste donc __parameters__
et __args__
.
>>> str_to_bool_dict.__args__
(<class 'str'>, <class 'bool'>)
D'où la réponse.
Introspection autorise les instructions assert
de py.test
à rendre les frameworks de test dérivés de JUnit obsolètes. Même les langages comme JavaScript/Elm/Clojure n’ont pas de fonction aussi simple que dir
of Python. La convention de nommage de Python vous permet de découvrir la langue sans lire réellement (documentant dans certains cas comme celui-ci) les documentations.
Alors, recherchez l'introspection et lisez la documentation/les listes de diffusion pour confirmer vos conclusions.
P.S. To OP - cette méthode répond également à votre question Quelle est la bonne façon de vérifier si un objet est un typing.Generic? utilisez la découverte si vous ne pouvez pas vous inscrire à la liste de diffusion ou si vous êtes un développeur occupé - c’est la façon de le faire en python.