Tapez les annotations pour Python2 dans les fichiers stub!

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.

Stub est né

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.

La cible est

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.

À quoi ça ressemble

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

La description

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.

Chaîne

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 desbytes, ʻAnyStr est disponible.

Nombres

Il semble qu'il n'y ait pas de génériques pour ʻintetfloat. 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.

ʻUnion 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.

alias

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.

Génériques

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

Tapez les annotations pour Python2 dans les fichiers stub!
Exemple de gestion des fichiers eml en Python
Rechercher des chaînes dans les fichiers
Techniques de tri en Python
Recherche récursive de fichiers et de répertoires en Python et sortie
Conversion de type entier pour chaque colonne de dataframe en python
À propos de "for _ in range ():" de python
Translocation de fichiers CSV avec Python Partie 1
Rechercher les fuites de mémoire dans Python
Rechercher des commandes externes avec python
Définition du type d'argument de fonction en python
Python pour les super débutants Super débutants Python # dictionnaire type 1
Manipuler des fichiers et des dossiers en Python
Charger dynamiquement les types json avec python
Gestion des fichiers JSON en Python
Téléchargez des fichiers Google Drive en Python
Type spécifié en python. Lancer des exceptions
Trier les gros fichiers texte en Python
Lire des fichiers en parallèle avec Python
Exporter et exporter des fichiers en Python
Exécutez unittest en Python (pour les débutants)
Python pour les super débutants Super débutants Python # dictionnaire type 2
Extraire des chaînes de fichiers avec Python
Trouver des fichiers comme Linux Find en Python
Arborescence de sortie des fichiers en Python
Inject est recommandé pour DDD en Python
Conseils pour gérer les binaires en Python
Résumé de diverses instructions for en Python
Référence du fichier INI en Python ou Ruby
Modèle pour l'écriture de scripts batch en python
Automatisez les tâches en manipulant des fichiers en Python
Traiter plusieurs listes avec for en Python
MongoDB avec Python pour la première fois
Lire et écrire des fichiers JSON avec Python
Obtenez un jeton pour conoha avec python
Fiche de triche AtCoder en python (pour moi-même)
J'ai cherché un nombre premier avec python
Remarques sur l'utilisation de python (pydev) avec eclipse
Conseils pour créer de petits outils avec python
Utilisez pathlib dans Maya (Python2.7) en préparation du prochain Python3.7
Téléchargez des fichiers dans n'importe quel format en utilisant Python
30/10/2016 else pour Python3> pour:
Modèle pour créer des applications de ligne de commande en Python
Quadtree en Python --2
Python en optimisation
python [pour moi]
CURL en Python
CERTIFICATE_VERIFY_FAILED dans Python 3.6, le programme d'installation officiel de macOS
Métaprogrammation avec Python
++ et-ne peuvent pas être utilisés pour incrémenter / décrémenter en python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Convertir le fichier FBX en ASCII <-> BINARY en Python
Type numérique Python
Méta-analyse en Python
Unittest en Python
Résumé de la façon d'importer des fichiers dans Python 3
Époque en Python