Geben Sie Anmerkungen für Python2 in Stub-Dateien ein!

def main(args: Any) -> None: Der Reiz von Python besteht darin, dass Sie es aufrufen können, ohne den Typ anzugeben. Dank dessen kann sogar ein kleines Skript, das in wenigen Minuten geschrieben wurde, die meisten Dinge tun. Aber weil es zu dynamisch ist, kann es mit zunehmender Größe nach hinten losgehen. Da die Menge an Informationen bekannt ist, die das menschliche Gehirn gleichzeitig speichern kann, kann es aufgrund einer Typfehlanpassung irgendwo zu einem Problem kommen. Professionelle Programmierer, die von diesem Gedanken angewidert waren. Dann sollte Python auch typbewusst sein.

Dank dessen ist es ab Python 3.5 möglich, den Typ im Argument und den Rückgabewert der Funktion anzugeben. Als eine der Optionen liegt es im Ermessen des Benutzers, das Gefühl zu haben, dass er es tun kann, wenn er es tun möchte.

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 wird Ende dieses Jahres (2016) verfügbar sein. Es wird möglich sein, dies weiterzuentwickeln und den Typ auch für Variablen anzugeben.

from typing import List, Dict
primes: List[int] = []

captain: str  # Note: no initial value!

class Starship:
   stats: Dict[str, int] = {}

Aus Was ist neu in Python 3.6

Wenn Sie jedoch den Typ in den Hauptteil des Codes schreiben, funktioniert dieser Code im zweiten System natürlich nicht. Für die Arbeit mit 3 oder 2 stehen großartige Alternativen zur Verfügung. Es unterscheidet sich von der im Kommentar geschriebenen Dokumentzeichenfolge. Nur die Typinformationen werden nach außen ausgeschnitten.

Stub wurde geboren

Mit anderen Worten, erstellen Sie eine Datei, die nur die Typinformationen enthält, und führen Sie basierend darauf die Typprüfung des vorherigen Codes durch. Dies wird als Stub-Datei bezeichnet, die in PEP 484 vorgeschlagen wurde. Im Inneren befindet sich das Skelett des Python-Codes, den Sie überprüfen möchten. Wenn Sie dies an ein Tool übergeben, das über eine Typprüffunktion verfügt, wird auf die Ursache des Problems hingewiesen. mypy (Vorgehensweise bei mypy: [Erstellen von Stubs für Python-Module](https: / Es kann mit /github.com/python/mypy/wiki/Creating-Stubs-For-Python-Modules "Stubs für Python-Module erstellen")) und PyCharm verwendet werden. Die Art und Weise, die Datei selbst zu schreiben, ist für beide gleich.

Das Ziel ist

Für diejenigen, die sagen: "Ich kenne die Struktur meines Moduls, möchte aber die Code-Vervollständigung bei Verwendung der Bibliothek intelligenter gestalten" [typisiert: Sammlung von Bibliotheksstubs für Python mit statischen Typen](https: // github.com/python/typeshed "python / typesshed: Sammlung von Bibliotheksstubs für Python mit statischen Typen"). Freiwillige haben Stub-Dateien für Standardmodule und externe Bibliotheken erstellt. Wenn Sie es auf Skripte anwenden, die keine Bibliothek sind, können Sie sie unabhängig von der Python-Version ausführen. Ich halte es auch für einen Vorteil, dass die Entwicklung einfacher ist, da die Genauigkeit der IDE-Komplementierung verbessert wird.

Wie ist es

Lass es uns tatsächlich schaffen. Die Erweiterung der Stub-Datei lautet ".pyi". Legen Sie es in dasselbe Verzeichnis wie den Code, den Sie überprüfen möchten. Nachdem Sie die Typinformationen in den Stub verschoben haben, können Sie sie löschen, wenn Sie eine an den Code-Body angehängt haben. PyCharm hat übrigens kein ".pyi" in der neu erstellten Liste. Es gibt so etwas nicht, aber wenn Sie es manuell erstellen, wird es automatisch erkannt und Sie können von nun an darauf verweisen. Die Priorität des Typ-Ratens scheint docstring <direktes Schreiben in Code <stub zu sein.


Before Angenommen, Sie haben diesen Code. Es mag unnatürlicher Code sein, weil ich ihn zur Erklärung mit so vielen Elementen wie möglich erstellt habe, aber er funktioniert vorerst.

Zuallererst gewöhnlicher Code, der überall ohne Typinformationen ist.

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"String": u"Mojimoji"}, FooLogger())
print(r.get_infos(["args", "origin"]))
print(r.get_infos("origin"))

Wenn Sie dem Typ Informationen hinzufügen, sieht dies folgendermaßen aus. Zu diesem Zeitpunkt war es exklusiv für 3er.

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", "String": "Mojimoji"}, FooLogger())
print(r.get_infos(["args", "origin"]))
print(r.get_infos("origin"))

After

Der Inhalt der Stub-Datei hierfür ist wie folgt. Die Notation # type: wird verwendet, um den Typ der Variablen anzugeben.

from typing import List, TypeVar, Union, Dict, Text, overload
import logging
import requests


#alias
DatabaseType = Dict[Text , Union[int, Text , Dict[Text , Text], None]]

#Generika
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

Erläuterung

Zunächst gibt der Stub einen Überblick über den Code, sodass Sie keine Implementierung schreiben müssen. Der Hauptteil des Prozesses wird mit "..." weggelassen. Es gibt auch einige Argumente und Konstanten, für die Anfangswerte festgelegt werden, aber alle sind "...". Daher ist dies eine Python-ähnliche Alternative und kann nicht ausgeführt werden.

@overload Tatsächlich gibt es nur ein Element, das Stub eigen ist. Andere sind die gleichen wie die Verwendung des Schreibmoduls selbst. Einer von ihnen ist dies. Im obigen Code gibt get_infos () ein Wörterbuch mit einer Liste und eine Zeichenfolge mit einer Zeichenfolge zurück. Wie der Körper, def get_infos(self, queue: Union[List[str], str]) -> Union[DatabaseType, str]: Wenn Sie schreiben, können Sie nicht zwischen Liste → Liste und Liste → Zeichenfolge unterscheiden. Hier kommt die Überlastung ins Spiel. Sie können die Kombination von Argument- und Rückgabetypen verdeutlichen.

String

In Anbetracht der Entsprechung von 2 Systemen ist es unnatürlich, wenn der Zeichenkettentyp "str" ist. "Text" verhält sich als "Zeichenfolge", als "Str" in der 3. Reihe und als "Unicode" in der 2. Reihe. Wenn Sie "Bytes" einschließen möchten, wird "AnyStr" bereitgestellt.

Zahlen

Es scheint, dass es keine Generika für "int" und "float" gibt. Damit T = TypeVar('T', int, float) Ist es sicher zu sagen?

List, Tuple, Dict usw.

Es entspricht der üblichen "Liste", "Tupel" und "Dikt". Ich importiere aus dem Tippmodul, aber es ist in Ordnung, stattdessen das untere zu verwenden. Denn wenn man sich die Implementierung ansieht

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)

Weil es so ist, scheint es nicht viel anders zu sein als nur "list ()". Übrigens bedeutet "Dict [str, str]" "Schlüsseltyp ist str, Werttyp ist str". Dict [str] ist ungültig.

"Union" und "Optional"

Union wird wörtlich verwendet, um etwas zu beschreiben, das eine Kombination von etwas ist. "Union [int, str]" bedeutet, dass sowohl int als auch str empfangen (oder zurückgegeben) werden können. Optional stellt eines der Elemente der Union "Keine" dar. Mit anderen Worten Optional[str] == Union[str, None] ist. Es ist (vielleicht) realisiert Null Sicherheit, was heutzutage ein heißes Thema ist.

alias

get_infos () gibt ein Wörterbuch zurück. Natürlich reicht es aus, nur Dict zu schreiben, aber was ist, wenn Sie es detailliert definieren? Dict[str, Dict[str, Union[int, str, List[str]]]] Es ist mühsam, so etwas immer und immer wieder zu schreiben. Kopieren und Einfügen ist die Quelle von Fehlern. Runden wir es in eine Variable. Dies wird als Alias bezeichnet.

Generika

FooLogger ist eine Klasse für die Protokollierung, aber sein spezifischer Name spielt für den Hauptprozess keine Rolle, es ist nur wichtig, ob er die Protokollierung erbt. Ich benutze dies zu solchen Zeiten. So schreiben Sie Generika im Python-Stil: T = TypeVar (" T ", bound = logging.Logger) In diesem Fall ist "T" eine Unterklasse der Protokollierung. Im Allgemeinen ist es üblicher, "T = TypeVar (" T ")" zu schreiben, ohne "bound" anzugeben.

Übrigens ist "LoggerType = TypeVar (" T ")" nutzlos. Der Variablenname und der Typname in der Zeichenfolge müssen übereinstimmen.

Recommended Posts

Geben Sie Anmerkungen für Python2 in Stub-Dateien ein!
Beispiel für den Umgang mit EML-Dateien in Python
Suchen Sie nach Zeichenfolgen in Dateien
Techniken zum Sortieren in Python
Suchen Sie rekursiv nach Dateien und Verzeichnissen in Python und geben Sie sie aus
Konvertierung des gesamten Typs für jede Datenrahmenspalte von Python
Über "für _ in range ():" von Python
Verschieben von CSV-Dateien mit Python Teil 1
Überprüfen Sie Python auf Speicherlecks
Suchen Sie mit Python nach externen Befehlen
Definition des Funktionsargumenttyps in Python
Python für Super-Anfänger Super-Anfänger Python # Wörterbuch Typ 1
Bearbeiten Sie Dateien und Ordner in Python
Laden Sie JSON-Typen dynamisch mit Python
Umgang mit JSON-Dateien in Python
Laden Sie Google Drive-Dateien in Python herunter
Typ in Python angegeben. Ausnahmen auslösen
Sortieren Sie große Textdateien in Python
Lesen Sie Dateien parallel zu Python
Exportieren und Ausgeben von Dateien in Python
Führen Sie unittest in Python aus (für Anfänger)
Python für Super-Anfänger Super-Anfänger Python # Wörterbuch Typ 2
Extrahieren Sie mit Python Zeichenfolgen aus Dateien
Suchen Sie nach Dateien wie Linux Find in Python
Ausgabebaumstruktur von Dateien in Python
Inject wird für DDD in Python empfohlen
Tipps zum Umgang mit Binärdateien in Python
Zusammenfassung verschiedener for-Anweisungen in Python
Referenz der INI-Datei in Python oder Ruby
Vorlage zum Schreiben von Batch-Skripten in Python
Automatisieren Sie Jobs, indem Sie Dateien in Python bearbeiten
Verarbeiten Sie mehrere Listen mit for in Python
MongoDB mit Python zum ersten Mal
Lesen und schreiben Sie JSON-Dateien mit Python
Holen Sie sich ein Zeichen für Conoha mit Python
AtCoder Spickzettel in Python (für mich)
Ich habe mit Python nach einer Primzahl gesucht
Hinweise zur Verwendung von Python (Pydev) mit Eclipse
Tipps zum Erstellen kleiner Werkzeuge mit Python
Verwenden Sie pathlib in Maya (Python2.7), um sich auf das kommende Python3.7 vorzubereiten
Laden Sie Dateien in jedem Format mit Python herunter
2016-10-30 sonst für Python3> für:
Vorlage zum Erstellen von Befehlszeilenanwendungen in Python
Quadtree in Python --2
Python in der Optimierung
Python [für mich]
CURL in Python
CERTIFICATE_VERIFY_FAILED in Python 3.6, dem offiziellen Installationsprogramm für macOS
Metaprogrammierung mit Python
++ und-können nicht zum Inkrementieren / Dekrementieren in Python verwendet werden
Python 3.3 mit Anaconda
Geokodierung in Python
SendKeys in Python
Konvertieren Sie die FBX-Datei in Python in ASCII <-> BINARY
Numerischer Python-Typ
Metaanalyse in Python
Unittest in Python
Zusammenfassung zum Importieren von Dateien in Python 3
Epoche in Python