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] = {}
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.
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.
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.
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
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.
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.
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 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.
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.
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