J'utilise Python 3.5 avec Mypy pour avoir une vérification statique de base pour mon script. Récemment, j'ai refactorisé certaines méthodes pour renvoyer OrderedDict, mais je suis tombé sur une erreur "'type' object is not subscriptable", quand j'ai essayé d'utiliser l'annotation de retour avec les types Key et Value spécifiés.
Exemple réduit:
#!/usr/bin/env python3.5
from collections import OrderedDict
# this works
def foo() -> OrderedDict:
result = OrderedDict() # type: OrderedDict[str, int]
result['foo'] = 123
return result
# this doesn't
def foo2() -> OrderedDict[str, int]:
result = OrderedDict() # type: OrderedDict[str, int]
result['foo'] = 123
return result
print(foo())
Et ceci est python sortie quand il est exécuté:
Traceback (most recent call last):
File "./foo.py", line 12, in <module>
def foo2() -> OrderedDict[str, int]:
TypeError: 'type' object is not subscriptable
Mypy n'a cependant aucun problème avec l'annotation de type en commentaire et va en fait avertir si j'essaye de faire result[123] = 123
.
Quelle est la cause de cela?
Il n'y a pas de problème dans mypy (du moins, pas en 0.501). Mais il y a is un problème avec Python 3.6.0. Considérez ce qui suit:
from collections import OrderedDict
from typing import Dict
def foo() -> Dict[str, int]:
result: OrderedDict[str, int] = OrderedDict()
result['two'] = 2
return result
Ce code satisfera à la fois mypy (0.501) et Python (3.6.0). Cependant, si vous remplacez Dict
par OrderedDict
, alors mypy sera toujours heureux, mais son exécution mourra avec TypeError: 'type' object is not subscriptable
.
Il est intéressant de noter que l'interpréteur Python meurt en voyant un OrderedDict
en indice dans la signature de la fonction, mais est heureux de l'accepter dans une annotation de type variable.
Quoi qu'il en soit, ma solution consiste à utiliser Dict
au lieu de OrderedDict
dans la signature de la fonction (et ajouter un commentaire que cela devrait être corrigé si/quand le Python l'interprète apprendra à accepter la signature correcte).
Comme solution de contournement, vous pouvez également mettre le type de retour dans une chaîne pour satisfaire à la fois Mypy et Python 3.6:
from collections import OrderedDict
def foo() -> 'OrderedDict[str, int]':
result = OrderedDict()
result['foo'] = 123
return result
Vous pouvez également essayer d'utiliser MutableMapping
(comme dans cette réponse: https://stackoverflow.com/a/44167921/138661 )
from collections import OrderedDict
from typing import Dict
def foo() -> MutableMapping[str, int]:
result = OrderedDict() # type: MutableMapping[str, int]
result['foo'] = 123
return result