def main(args: Any) -> None: L'intérêt de Python est que vous pouvez l'appeler sans spécifier le type. Grâce à cela, même un petit script écrit en quelques minutes peut faire l'essentiel du travail. Mais parce qu'il est trop dynamique, il peut se retourner contre lui à mesure qu'il prend de l'ampleur. Étant donné que la quantité d'informations que le cerveau humain peut contenir à un moment donné est connue, il peut y avoir un problème quelque part en raison d'une incompatibilité de type. Des programmeurs professionnels dégoûtés de cette pensée. Ensuite, Python doit également être sensible au type.
Grâce à cela, à partir de Python 3.5, il est possible de spécifier le type dans l'argument et la valeur de retour de la fonction. En tant qu'une des options, il est laissé à la discrétion de l'utilisateur de sentir qu'il / elle peut le faire s'il / elle le souhaite.
def fizzbuzz(num: int) -> None:
[print("fizzbuzz") if not x % 15
else print("fizz") if not x % 5
else print("buzz") if not x % 3
else print(x) for x in range(num)]
Python3.6 sera disponible d'ici la fin de cette année (2016). Il sera possible de développer davantage cela et de spécifier également le type des variables.
from typing import List, Dict primes: List[int] = [] captain: str # Note: no initial value! class Starship: stats: Dict[str, int] = {}
Depuis [Quoi de neuf dans Python 3.6](https://docs.python.org/3.6/whatsnew/3.6.html «Quoi de neuf dans Python 3.6 - Documentation Python 3.6.0b4»)
Mais bien sûr, si vous écrivez le type dans le corps du code, ce code ne fonctionnera pas dans le 2ème système. De bonnes alternatives sont disponibles pour travailler avec 3 ou 2. Il est différent de la docstring écrite dans le commentaire. Seules les informations de type sont découpées vers l'extérieur.
En d'autres termes, créez un fichier contenant uniquement les informations de type et, sur cette base, effectuez la vérification de type du code précédent. C'est ce qu'on appelle un fichier stub, qui a été proposé dans PEP 484. À l'intérieur se trouve le squelette du code Python que vous souhaitez vérifier. Si vous le transmettez à un outil doté d'une fonction de vérification de type, il indiquera la source du défaut. mypy (Comment faire avec mypy: [Création de stubs pour les modules Python](https: / Il peut être utilisé avec /github.com/python/mypy/wiki/Creating-Stubs-For-Python-Modules "Création de stubs pour les modules Python")) et PyCharm. La façon d'écrire le fichier lui-même est la même pour les deux.
Pour ceux qui disent: "Je connais la structure de mon propre module, mais je veux rendre la complétion de code plus intelligente lors de l'utilisation de la bibliothèque" [typeshed: Collection de stubs de bibliothèque pour Python, avec des types statiques](https: // github.com/python/typeshed "python / typesshed: Collection de stubs de bibliothèque pour Python, avec des types statiques"). Les volontaires ont créé des fichiers stub pour les modules standard et les bibliothèques externes. Le but de l'appliquer à des scripts non-bibliothèque est de leur permettre de s'exécuter quelle que soit la version de Python. Aussi, je pense que c'est un avantage qu'il est plus facile à développer car la précision de la complémentation IDE est améliorée.
Faisons-le réellement. L'extension du fichier stub est «.pyi». Placez-le dans le même répertoire que le code que vous souhaitez inspecter. Une fois que vous avez déplacé les informations de type vers le stub, vous pouvez les supprimer si vous en avez une attachée au corps du code. Au fait, PyCharm n'a pas «.pyi» dans la liste nouvellement créée. Cela n'existe pas, mais si vous le créez manuellement, il sera automatiquement reconnu et vous pourrez désormais vous y référer. La priorité de deviner le type semble être docstring <écriture directe dans le code <stub.
Before Supposons que vous ayez ce code. Ce n'est peut-être pas du code naturel car je l'ai fait avec autant d'éléments que possible pour l'explication, mais cela fonctionne pour le moment.
Tout d'abord, du code ordinaire partout sans aucune information de type.
import json
import logging
import requests
import sys
class Resources:
POST_URL = "https://httpbin.org/post"
def __init__(self, auth, logger):
self.auth = auth
self.logger = logger
self.session = self.get_session()
self.res = self.get_resources()
def get_session(self):
return requests.session()
def get_resources(self):
return json.loads(self.session.post(
self.POST_URL, params=self.auth).text)
def get_infos(self, queue):
if isinstance(queue, str):
return str(self.res.get(queue, ""))
else:
return {key: self.res.get(key, "") for key in queue}
class FooLogger(logging.Logger):
def __init__(self):
super(FooLogger, self).__init__("foobar", logging.INFO)
self.logger = logging.getLogger()
log_stdout = logging.StreamHandler(sys.stdout)
self.addHandler(log_stdout)
r = Resources({"name": "watashi", u"Chaîne": u"Mojimoji"}, FooLogger())
print(r.get_infos(["args", "origin"]))
print(r.get_infos("origin"))
Si vous ajoutez des informations de type à ceci, cela ressemblera à ceci. À ce stade, c'était exclusivement pour 3 séries.
from typing import List, TypeVar, Union, Dict, Text
import json
import logging
import requests
import sys
DatabaseType = Dict[Text, Union[int, Text, Dict[Text, Text], None]]
LoggerType = TypeVar("LoggerType", bound=logging.Logger)
class Resources:
POST_URL = "https://httpbin.org/post"
def __init__(self, auth: Dict[Text, Text], logger: LoggerType) -> None:
self.auth = auth
self.logger = logger
self.session = self.get_session()
self.res = self.get_resources()
def get_session(self) -> requests.Session:
return requests.session()
def get_resources(self) -> Dict:
return json.loads(self.session.post(
self.POST_URL, params=self.auth).text)
def get_infos(self, queue: Union[List[Text], Text]) ->\
Union[DatabaseType, Text]:
if isinstance(queue, Text):
return str(self.res.get(queue, ""))
else:
return {key: self.res.get(key, "") for key in queue}
class FooLogger(logging.Logger):
def __init__(self) -> None:
super().__init__("foobar", logging.INFO)
self.logger = logging.getLogger()
log_stdout = logging.StreamHandler(sys.stdout)
self.addHandler(log_stdout)
r = Resources({"name": "watashi", "Chaîne": "Mojimoji"}, FooLogger())
print(r.get_infos(["args", "origin"]))
print(r.get_infos("origin"))
After
Le contenu du fichier stub à cet effet est le suivant. La notation «# type:» est utilisée pour spécifier le type de la variable.
from typing import List, TypeVar, Union, Dict, Text, overload
import logging
import requests
#alias
DatabaseType = Dict[Text , Union[int, Text , Dict[Text , Text], None]]
#Génériques
LoggerType = TypeVar("LoggerType", bound=logging.Logger)
class Resources:
POST_URL = ... # type: Text
def __init__(self, auth: Dict[Text , Text], logger: LoggerType) -> None:
self.auth = ... # type: Dict[Text , Text]
self.logger = ... # type: LoggerType
self.session = ... # type: requests.Session
self.res = ... # type: Dict
def get_session(self) -> requests.Session: ...
def get_resources(self) -> Dict: ...
@overload
def get_infos(self, queue: Text) -> Text: ...
@overload
def get_infos(self, queue: List[Text]) -> DatabaseType: ...
class FooLogger(logging.Logger):
def __init__(self) -> None:
super().__init__(self, ...)
self.logger = ... # type: LoggerType
Tout d'abord, le stub donne un aperçu du code, vous n'avez donc pas besoin d'écrire une implémentation. Le corps principal du processus est omis avec "...". De plus, certains arguments et constantes ont des valeurs initiales, mais ils sont tous "...". Par conséquent, il s'agit d'une alternative semblable à Python et ne peut pas être exécutée.
@overload
En fait, il n'y a qu'un seul élément propre au stub. D'autres sont identiques à l'utilisation du module de saisie lui-même. L'un d'eux est celui-ci.
Dans le code ci-dessus, get_infos () renvoie un dictionnaire avec une liste et une chaîne avec une chaîne. Comme le corps,
def get_infos(self, queue: Union[List[str], str]) -> Union[DatabaseType, str]:
Si vous écrivez, vous ne pouvez pas faire la distinction entre liste → liste et liste → chaîne de caractères. C'est là que la surcharge entre en jeu. Vous pouvez clarifier la combinaison des types d'argument et de retour.
Compte tenu de la correspondance de 2 systèmes, il n'est pas naturel que le type de chaîne de caractères soit «str». Text
se comporte comme une" chaîne ", comme str
dans la troisième série et comme ʻunicodedans la deuxième série. Si vous voulez inclure des
bytes, ʻAnyStr
est disponible.
Il semble qu'il n'y ait pas de génériques pour ʻintet
float. Alors
T = TypeVar('T', int, float)`
Est-il prudent de le dire?
Liste
, Tuple
, Dict
, etc.Il correspond aux habituels «list», «tuple» et «dict». J'importe depuis le module de saisie, mais vous pouvez utiliser le module inférieur à la place. Parce que quand on regarde l'implémentation
class List(list, MutableSequence[T], extra=list):
def __new__(cls, *args, **kwds):
if _geqv(cls, List):
raise TypeError("Type List cannot be instantiated; "
"use list() instead")
return list.__new__(cls, *args, **kwds)
Parce que c'est le cas, il semble que ce n'est pas très différent de simplement list ()
. Au fait, Dict [str, str]
signifie "le type de clé est str, le type de valeur est str". Dict [str]
n'est pas valide.
et ʻOptional
L'Union est littéralement utilisée pour décrire quelque chose qui est une combinaison de quelque chose.
ʻUnion [int, str] indique que les deux int et str peuvent être reçus (ou retournés). Facultatif représente l'un des éléments de l'Union est «Aucun». En d'autres termes
Optional[str] == Union[str, None]`
est. Il réalise (peut-être) une sécurité nulle, qui est un sujet brûlant ces jours-ci.
get_infos () renvoie un dictionnaire. Bien sûr, il suffit d'écrire Dict, mais que faire si vous le définissez en détail?
Dict[str, Dict[str, Union[int, str, List[str]]]]
C'est compliqué d'écrire encore et encore une chose aussi longue. Le copier-coller est la source de bogues. Arrondissons-le en une variable. C'est ce qu'on appelle un alias.
FooLogger est une classe pour la journalisation, mais son nom spécifique n'a pas d'importance pour le processus principal, il importe simplement de savoir s'il hérite de la journalisation. J'utilise ceci à de tels moments. Voici comment écrire des génériques de style Python: T = TypeVar (" T ", bound = logging.Logger)
Dans ce cas, «T» est une sous-classe de journalisation. En général, il est plus courant d'écrire T = TypeVar (" T ")
sans spécifier bound
.
Au fait, LoggerType = TypeVar (" T ")
est inutile. Le nom de la variable et le nom du type dans la chaîne doivent correspondre.
Recommended Posts