Guten Tag, Freunde. Wir erhöhen weiterhin die Intensität des Starts neuer Kurse und freuen uns, Ihnen mitteilen zu können, dass die Kurse des Kurses
"Webentwickler in Python" Ende April beginnen werden. In dieser Hinsicht teilen wir traditionell die Übersetzung von nützlichem Material. Fangen wir an.
Python ist als dynamische Schreibsprache bekannt. Es ist sehr einfach, DSL-ähnliche Frameworks zu schreiben, die mit statischen Typprüfungstools nur schwer zu analysieren sind. Trotzdem können
wir mit den neuesten funktionalen Innovationen von
mypy wie
Protokollen und
Literaltypen sowie der grundlegenden Unterstützung für Metaklassen und Deskriptorunterstützung häufig genaue Typen erhalten, aber es ist immer noch schwierig, falsch positive und andere negative Faktoren zu vermeiden. Um dieses Problem zu lösen und zu vermeiden, dass das Typsystem für jedes Framework
angepasst werden muss, unterstützt
mypy ein
Plug-In- System. Plugins sind Module in Python, die Plugin-Hooks bereitstellen, die
mypy aufruft , wenn die Arten von Klassen und Funktionen überprüft werden, die mit einer Bibliothek oder einem Framework interagieren. Somit ist es möglich, den Typ der zurückgegebenen Funktion, der ansonsten äußerst schwierig auszudrücken ist, genauer zu unterscheiden oder automatisch einige Klassenmethoden zu generieren, um die Auswirkungen des Dekorateurs widerzuspiegeln. Weitere Informationen zur Architektur des Plug-In-Systems und die vollständige Liste der Funktionen finden Sie in der
Dokumentation .
Verwandte Plugins für die StandardbibliothekMypy enthält Standard-Plugins zum Implementieren grundlegender Funktionen und Klassen sowie
dataclasses
für
ctypes
,
dataclasses
und
dataclasses
. Es enthält auch Plugins für
attrs
(es war in der Vergangenheit das erste Plugin eines Drittanbieters, das für
mypy geschrieben wurde ). Mit diesen Plugins kann
mypy mithilfe dieser Bibliotheksfunktionen Typen genauer bestimmen und den Code korrekt auf Typ überprüfen. Um dies anhand eines Beispiels zu zeigen, sehen Sie sich ein Code-Snippet an:
from dataclasses import dataclass from typing import Generic, TypeVar @dataclass class TaggedVector(Generic[T]): data: List[T] tag: str position = TaggedVector([0, 0, 0], 'origin')
Oben wird
get_class_decorator_hook()
aufgerufen, wenn die Klasse definiert wird. Dadurch werden dem Funktionskörper automatisch generierte Methoden
__init__()
, einschließlich
__init__()
.
Mypy verwendet einen solchen Konstruktor, um
TaggedVector[int]
als
position
korrekt zu berechnen. Wie Sie dem Beispiel entnehmen können, funktionieren Plugins auch mit generischen Klassen.
Hier ist ein weiterer Code:
from contextlib import contextmanager @contextmanager def timer(title: str) -> Iterator[float]: ... with timer(9000) as tm: ...
Hier gibt
get_function_hook()
den genauen Rückgabetyp für den
contextmanager
Dekorator an, sodass Aufrufe der dekorierten Funktion auf Übereinstimmung mit einem bestimmten Typ überprüft werden können. Jetzt kann
mypy den Fehler erkennen: Das Argument für
timer()
sollte eine Zeichenfolge sein.
Eine Kombination aus Plugins und StubsNeben der Verwendung dynamischer Python-Funktionen stoßen Frameworks häufig auf das Problem großer APIs.
Mypy benötigt
Stub- Dateien für Bibliotheken, um den Code zu testen, der diese Bibliotheken verwendet (nur wenn die Bibliothek keine integrierten Anmerkungen enthält, was nicht so häufig vorkommt). Das Verteilen von Stubs für große Frameworks mit
typisierten Daten ist keine gängige Praxis:
- Typeshed hat einen relativ langsamen Release-Zyklus (im Lieferumfang von mypy enthalten ).
- Unvollständige Stubs können zu falschen Anrufen führen, die äußerst schwer zu vermeiden sind.
- Mischen Sie nicht nur Stubs aus verschiedenen typisierten Versionen.
In
PEP 561 eingeführte Stub-Pakete führen Folgendes aus:
- Entwickler können Stub-Pakete so oft veröffentlichen, wie sie möchten.
- Benutzer, die sich nicht für die Verwendung des Pakets entschieden haben, sehen keine Fehlalarme.
- Sie können beliebige Versionen mehrerer verschiedener Stub-Pakete sicher installieren.
Darüber hinaus können Sie mit
pip
verschiedene Stubs für Bibliotheken und die entsprechenden
mypy- Plugins in einer Distribution kombinieren. Stubs für das
mypy- Framework oder das entsprechende Plugin können einfach entwickelt und zu einer Distribution zusammengefasst werden.
Dies ist äußerst nützlich, da Plugins fehlende oder ungenaue Definitionen in Stubs ausfüllen.
Das neueste Beispiel für ein solches Paket sind
SQLAlchemy-Stubs und -Plugins mit der ersten öffentlichen Version von Version 0.1, die vor einiger Zeit auf PyPI veröffentlicht wurde. Trotz der Tatsache, dass dieses Projekt in der frühen Alpha-Version vorliegt, können wir es sicher in DropBox verwenden, um die Typprüfung zu verbessern. Das Plugin versteht die grundlegenden ORM-Deklarationen:
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String)
Im obigen Code-Snippet verwendet das Plugin
get_dynamic_class_hook()
, um
mypy mitzuteilen, dass Base eine gültige Basisklasse ist, auch wenn es nicht so aussieht. Anschließend wird
get_base_class_hook()
aufgerufen, um den Benutzer zu definieren, und es werden mehrere automatisch generierte Attribute
get_base_class_hook()
. Als Nächstes erstellen wir eine Instanz des Modells:
user = User(id=42, name=42)
get_function_hook()
aufgerufen, daher kann
mypy einen Fehler anzeigen: Anstelle des Benutzernamens wird ein
integer
Wert empfangen.
Stubs definieren
Column
als
generischen Deskriptor, damit die Modellattribute die richtigen Typen erhalten:
id_col = User.id
Wir begrüßen PRs, die Stubs präzisere Typen hinzufügen (der Fortschritt für Kernmodule wird
hier verfolgt).
Hier sind einige Fallstricke, die wir bei der Arbeit an Steckern entdeckt haben:
- Verwenden Sie
__getattr__()
, um Fehlalarme in den frühen Phasen zu vermeiden, wenn Stubs nicht abgeschlossen sind (dies verhindert Mypy- Fehler, wenn Modulattribute fehlen). Sie können dies auch in __init__.py
Dateien verwenden, wenn Submodule fehlen. - Deskriptoren helfen häufig bei genaueren Typdefinitionen für den Zugriff auf benutzerdefinierte Attribute (wie im oben beschriebenen Spaltenbeispiel). Die Verwendung von Deskriptoren ist auch dann in Ordnung, wenn für die tatsächliche Implementierung der Laufzeit ein komplexerer Mechanismus verwendet wird, beispielsweise eine Metaklasse.
- Deklarieren Sie die Framework-Klassen ohne zu zögern als verallgemeinert. Trotz der Tatsache, dass sie zur Laufzeit nicht so sind, können Sie mit dieser Technik den Typ einiger Elemente des Frameworks genauer bestimmen, während Laufzeitfehler leicht umgangen werden können. (Wir hoffen, dass Frameworks nach und nach integrierte Unterstützung für generische Typen hinzufügen und die entsprechenden Klassen explizit von
typing.Generic
.)
Kürzlich veröffentlichte mypy PluginsFür die beliebten Python-Frameworks sind bereits mehrere Plugins verfügbar. Neben dem oben erwähnten
SQLAlchemy- Plugin enthalten andere bemerkenswerte Beispielpakete mit Stubs und das integrierte
mypy- Plugin Stubs für die
Django- und
Zope- Schnittstellen. An diesen Projekten wird aktiv gearbeitet.
Installieren und Verbinden von Stub- und Plugin-PaketenVerwenden Sie pip, um das Plugin-Paket für
mypy und / oder stub in einer virtuellen Umgebung zu installieren, in der
mypy bereits
installiert ist :
$ pip install sqlalchemy-stubs
Mypy erkennt installierte Stubs automatisch. Um installierte Plugins zu verbinden, fügen Sie sie direkt in mypy.ini (oder in die Benutzerkonfigurationsdatei) ein:
[mypy] plugins = sqlmypy, mypy_django_plugin.main
Mypy- Plugins entwickeln und Stubs schreiben
Wenn Sie ein Paket von Stubs und Plugins für das von Ihnen verwendete Framework entwickeln möchten, können wir
das Repository sqlalchemy-stubs als Vorlage verwenden. Es enthält eine
setup.py
, Infrastrukturtests mit datengesteuerten Tests und eine Beispiel-Plug-In-Klasse mit einer Reihe von Hooks für das Plug-In (Plugin-Hooks). Wir empfehlen die Verwendung von
stubgen , um die mit
mypy gelieferten Stubs automatisch zu generieren und sie zu verwenden.
Stubgen
hat sich in
mypy 0.670
Stubgen
mypy 0.670
verbessert.
Lesen Sie die
Dokumentation, wenn Sie mehr über das
mypy- Plugin-
System erfahren
möchten . Sie können auch im Internet nach den Quellcodes der im Artikel beschriebenen Plugins suchen. Wenn Sie Fragen haben, können Sie diese
hier stellen .
Der 15. April wird ein kostenloses
offenes Webinar über den Kurs sein, das von einem der Organisatoren der Moskauer Python-Community -
Vladimir Filonov - abgehalten wird.
Melden Sie sich an, es wird interessant sein. Und jetzt warten wir auf Ihre Kommentare zum übersetzten Material.