Indices de type ajoutés dans PEP484 depuis Python 3.5. Je me suis demandé s'il pouvait être appliqué au ndarray de numpy, il s'agit donc d'un outil de vérification statique de type hint mypy ) Et les résultats des enquêtes ww telles que le traitement des modules tiers sont résumés.
En conclusion, la vérification des indices de type de numpy.ndarray à l'aide de mypy est possible en utilisant numpy-stubs. Cependant, à partir de maintenant (janvier 2020), mypy check en spécifiant dtype et shape of ndarray n'est pas possible. D'un autre côté, si vous voulez ajouter des indices de type incluant dtype et shape comme annotations pour la lisibilité, l'option d'utiliser nptyping semble être bonne.
Au minimum, installez ce qui suit avec pip
. (L'environnement entre parenthèses est l'environnement au moment de ma vérification)
Tout d'abord, le contrôle de type était dans un état incertain, alors j'ai expérimenté.
# ex1.py
from typing import List, Tuple
def calc_center(points: List[Tuple[int, int]]) -> Tuple[float, float]:
'''Trouvez le centre de gravité dans la liste des points'''
n = len(points)
x, y = 0, 0
for p in points:
x += p[0]
y += p[1]
return x/n, y/n
points_invalid = [[1, 1], [4, 2], [3, 6], [-1, 3]]
print(calc_center(points_invalid)) # TypeHint Error
Le code ci-dessus, bien sûr, se termine normalement, mais je vais vérifier l'indice de type avec mypy.
Si vous avez installé mypy avec pip etc., vous devriez pouvoir exécuter mypy
dans le terminal.
>mypy ex1.py
ex1.py:16: error: Argument 1 to "calc_center" has incompatible type "List[List[int]]"; expected "List[Tuple[int, int]]"
Found 1 error in 1 file (checked 1 source file)
>python ex1.py
(1.75, 3.0)
De cette façon, il indique où l'indication de type enfreint. Si vous le modifiez comme suit, le contrôle par mypy passera.
# ex2.py
from typing import List, Tuple
def calc_center(points: List[Tuple[int, int]]) -> Tuple[float, float]:
'''Trouvez le centre de gravité dans la liste des points'''
n = len(points)
x, y = 0, 0
for p in points:
x += p[0]
y += p[1]
return x/n, y/n
points = [(1, 1), (4, 2), (3, 6), (-1, 3)]
print(calc_center(points)) # Success
>mypy ex2.py
Success: no issues found in 1 source file
Puisque le ndarray de numpy est pratique pour calculer les points de coordonnées, j'aimerais le changer en conséquence. Cependant, lorsque j'ajoute ʻimport numpy` au code précédent et que j'exécute mypy, l'erreur suivante se produit.
# ex3.py
from typing import List, Tuple
import numpy as np
def calc_center(points: List[Tuple[int, int]]) -> Tuple[float, float]:
'''Trouvez le centre de gravité dans la liste des points'''
n = len(points)
x, y = 0, 0
for p in points:
x += p[0]
y += p[1]
return x/n, y/n
points = [(1, 1), (4, 2), (3, 6), (-1, 3)]
print(calc_center(points)) # Success
>mypy ex3.py
ex3.py:4: error: No library stub file for module 'numpy'
ex3.py:4: note: (Stub files are from https://github.com/python/typeshed)
Found 1 error in 1 file (checked 1 source file)
La cause de l'erreur est que le package numpy lui-même ne prend pas en charge les indices de type. Ensuite, divisons les contre-mesures dans les trois cas suivants.
Cela semble être le plus simple et le plus courant. La méthode consiste à créer un fichier avec le nom mypy.ini, à écrire comme suit, puis à le placer dans le répertoire en cours.
[mypy]
[mypy-numpy]
ignore_missing_imports = True
Les 3e et 4e lignes sont définies pour ignorer l'erreur de vérification de l'indice de type pour numpy.
Si vous souhaitez l'appliquer à d'autres modules tiers, copiez les 3ème et 4ème lignes et modifiez la partie numpy
.
Pour les autres spécifications relatives à mypy.ini, veuillez vous référer à la page officielle ici.
Vous pouvez maintenant exécuter mypy check normalement. Cependant, notez que la vérification d'indication de type de ndarray lui-même est également ignorée (dernière ligne).
# ex4.py (ignore_missing_imports)
from typing import List, Tuple
import numpy as np
def calc_center(points: List[Tuple[int, int]]) -> Tuple[float, float]:
'''Trouvez le centre de gravité dans la liste des points'''
n = len(points)
x, y = 0, 0
for p in points:
x += p[0]
y += p[1]
return x/n, y/n
def calc_center_np(points: np.ndarray) -> np.ndarray:
'''Trouvez le centre de gravité dans la liste des points(version ndarray)'''
return np.average(points, axis=0)
points = [(1, 1), (4, 2), (3, 6), (-1, 3)]
print(calc_center(points)) # Success
np_points = np.array(points, dtype=np.int)
print(calc_center_np(np_points)) # Success
print(calc_center_np(points)) # Success ?
>mypy ex4.py
Success: no issues found in 1 source file
Créez une fonction vide (stub) pour l'indice de type du module que vous souhaitez utiliser et mypy les examinera à la place. Les fichiers stub sont gérés avec l'extension .pyi.
Un stub pour numpy numpy-stubs est disponible sur github.
Tout d'abord, apportez le dossier "numpy-stubs" avec git clone https: // github.com / numpy / numpy-stubs.git
etc.
Remplacez le dossier "numpy-stubs" par "numpy".
La structure des dossiers est la suivante.
numpy-stubs/
└── numpy
├── __init__.pyi
└── core
├── numeric.pyi
├── numerictypes.pyi
├── _internal.pyi
└── __init__.pyi
De plus, ajoutez le chemin du dossier racine où le stub est placé à la variable d'environnement MYPYPATH
et exécutez-le.
# ex5.py (numpy-stubs)
from typing import List, Tuple
import numpy as np
def calc_center(points: List[Tuple[int, int]]) -> Tuple[float, float]:
'''Trouvez le centre de gravité dans la liste des points'''
n = len(points)
x, y = 0, 0
for p in points:
x += p[0]
y += p[1]
return x/n, y/n
def calc_center_np(points: np.ndarray) -> np.ndarray:
'''Trouvez le centre de gravité dans la liste des points(version ndarray)'''
return np.average(points, axis=0)
points = [(1, 1), (4, 2), (3, 6), (-1, 3)]
print(calc_center(points)) # Success
np_points = np.array(points, dtype=np.int)
np_points_float = np.array(points, dtype=np.float)
print(calc_center_np(np_points)) # Success
print(calc_center_np(np_points_float)) # Success
print(calc_center_np(points)) # TypeHint Error
>set "MYPYPATH=numpy-stubs"
>mypy ex5.py
ex5.py:28: error: Argument 1 to "calc_center_np" has incompatible type "List[Tuple[int, int]]"; expected "ndarray"
Found 1 error in 1 file (checked 1 source file)
Maintenant, la vérification des indices de type de ndarray fonctionne. Cependant, il n'est pas possible de vérifier après avoir spécifié dtype et shape, et c'est un léger goulot d'étranglement que les variables d'environnement doivent être définies une par une.
stubgen
mypy est livré avec un script appelé stubgen qui génère automatiquement un fichier pour les indices de type (extension .pyi). ..
>stubgen -p numpy
-p
est une option pour générer récursivement des stubs pour les packages.
Lorsqu'il est exécuté, un dossier ʻout` est créé dans le répertoire courant et le fichier stub numpy y est compressé.
Cependant, j'obtiens une autre erreur lorsque j'exécute mypy check, probablement parce que stubgen n'est pas capable d'extraire correctement la structure de numpy. Il y a des cas où les stubs sont ouverts au public comme numpy-stubs, il est donc plus sûr de les utiliser si possible.
Si vous souhaitez créer un indice de type comprenant dtype et la forme de ndarray après avoir utilisé la méthode 1 ou la méthode 2, [nptyping](numpy-type-hints-in-python-pep- 484) doit être utilisé.
Il peut être installé depuis PyPi avec pip install nptyping
.
Bien que nptyping ne supporte pas la vérification des indices de type statique par mypy, les indices de type qui spécifient dtype et la forme de ndarray peuvent être spécifiés en utilisant l'alias ʻArray`.
Voici un échantillon officiel. Les tableaux avec des types mixtes tels que DataFrame de pandas sont également OK.
from nptyping import Array
Array[str, 3, 2] # 3 rows and 2 columns
Array[str, 3] # 3 rows and an undefined number of columns
Array[str, 3, ...] # 3 rows and an undefined number of columns
Array[str, ..., 2] # an undefined number of rows and 2 columns
Array[int, float, str] # int, float and str on columns 1, 2 and 3 resp.
Array[int, float, str, ...] # int, float and str on columns 1, 2 and 3 resp.
Array[int, float, str, 3] # int, float and str on columns 1, 2 and 3 resp. and with 3 rows
La vérification d'instance à l'aide de «cette instance» est également possible.
# ex6.py (nptyping)
from typing import List, Tuple
import numpy as np
from nptyping import Array
def calc_center(points: List[Tuple[int, int]]) -> Tuple[float, float]:
'''Trouvez le centre de gravité dans la liste des points'''
n = len(points)
x, y = 0, 0
for p in points:
x += p[0]
y += p[1]
return x/n, y/n
def calc_center_np(points: Array[int, ..., 2]) -> Array[float, 2]:
'''Trouvez le centre de gravité dans la liste des points(version ndarray)'''
print(isinstance(points, Array[int, ..., 2]))
return np.average(points, axis=0)
points = [(1, 1), (4, 2), (3, 6), (-1, 3)]
np_points = np.array(points, dtype=np.int)
np_points_float = np.array(points, dtype=np.float)
print(isinstance(calc_center_np(np_points), Array[float, 2])) #argument: True,Valeur de retour: True
print(isinstance(calc_center_np(np_points_float), Array[float, 2])) #argument: False,Valeur de retour: True
print(isinstance(calc_center_np(points), Array[float, 2])) #argument: False,Valeur de retour: True
N'oubliez pas de définir nptyping sur ʻignore_missing_imports = True` dans mypy.ini. Le résultat de l'exécution est le suivant.
>mypy ex6.py
Success: no issues found in 1 source file
>python ex6.py
True
True
False
True
False
True
J'ai résumé les indices de type autour de numpy. Je pense qu'il est courant de traiter les informations telles que les coordonnées et les données de table comme un ndarray et de mettre en œuvre des opérations géométriques et statistiques. À ce moment-là, je m'inquiète souvent du code que j'ai écrit, comme "Combien de dimensions de ndarray pétrissez-vous?" J'ai trouvé des conseils de type comme nptyping utiles en termes de lisibilité et de maintenabilité. Je pense que ce sera plus utile s'il peut prendre en charge la vérification de type par mypy à l'avenir.
https://stackoverflow.com/questions/52839427/ https://www.sambaiz.net/article/188/ https://masahito.hatenablog.com/entry/2017/01/08/113343
Recommended Posts