Ich gehe davon aus, dass Sie, die diesen Artikel lesen möchten, wissen, was Typoskript ist. Der Javascript-Entwickler hat Typescript erstellt, um Javascript typsicherer zu machen. Typesafe macht den Code lesbarer und weist weniger Fehler auf, ohne dass ein Test geschrieben werden muss. Kann Typsicherheit in Python erreicht werden?.
Stellen Sie sich diese unschuldig aussehende Funktion vor
def send_email(sender, receiver, message): ...
Ich verstecke absichtlich die Code-Implementierung. Können Sie anhand des Funktionsnamens und des Parameters erraten, wozu eine Funktion dient und welchen Parameter wir benötigen, um diese Funktion zu verwenden? Anhand des Funktionsnamens wissen wir, dass es sich um eine Funktion zum Versenden einer E-Mail handelt. Was ist mit dem Parameter? Was sollten wir eingeben, um diese Funktion zu verwenden?
Erste Vermutung: Absender ist die Zeichenfolge der E-Mail, Empfänger ist die Zeichenfolge der E-Mail, Nachricht ist die Zeichenfolge des E-Mail-Texts.
send_email(sender="john@mail.com", receiver="doe@mail.com", message="Hello doe! How are you?")
Die einfachste Vermutung. aber es ist nicht die einzige Vermutung.
Zweite Vermutung: Absender ist Ganzzahl der Benutzer-ID in der Datenbank, Empfänger ist Ganzzahl der Benutzer-ID in der Datenbank, Nachricht ist die Zeichenfolge des E-Mail-Texts.
john_user_id = 1 doe_user_id = 2 send_email(sender=1, receiver=2, message="Hello doe! How are you?")
Stellen Sie sich vor, Sie arbeiten an einer Anwendung. Die meisten Anwendungen verwenden eine Datenbank. Der Benutzer wird normalerweise durch seine ID repräsentiert.
Dritte Vermutung: Absender ist Wörterbuch, Empfänger ist Wörterbuch, Nachricht ist Wörterbuch.
john = { "id": 1, "username": "john", "email": "john@mail.com" } doe = { "id": 2, "username": "doe", "email": "doe@mail.com" } message = { "title": "Greeting my friend doe", "body": "Hello doe! How are you?" } send_email(sender=john, receiver=doe, message=message)
Vielleicht benötigt send_email mehr als E-Mail und Benutzer-ID. Um mehr Daten zu jedem Parameter hinzuzufügen, wird eine Wörterbuchstruktur verwendet. Sie bemerken, dass es sich bei der Nachricht nicht nur um eine Zeichenfolge handelt, sondern möglicherweise um einen Titel und einen Text.
Weitere Vermutung: Absender ist Klassenbenutzer, Empfänger ist Klassenbenutzer, Nachricht ist Wörterbuch.
class User(): def __init__(self, id, username, email): self.id = id self.username = username self.email = email john = User(id=1, username="john", email="john@mail.com") doe = User(id=2, username="doe", email="doe@mail.com") message = { "title": "Greeting my friend doe", "body": "Hello doe! How are you?" } send_email(sender=john, receiver=doe, message=message)
Vielleicht lässt sich send_email in eine Datenbank-Orm wie Django ORM oder Sqlalchemy integrieren. Um es dem Endbenutzer einfacher zu machen, wird direkt die ORM-Klasse verwendet.
Welche Antwort ist also die richtige? Eine davon kann eine richtige Antwort sein. Vielleicht kann die richtige Antwort eine Kombination aus zwei Vermutungen sein. Wie Sender und Empfänger ist die Klasse Benutzer (vierte Vermutung), aber die Nachricht ist str (erste Vermutung). Wir können nicht sicher sein, es sei denn, wir lesen die Code-Implementierung. Das ist Zeitverschwendung, wenn Sie ein Endbenutzer sind. Als Endbenutzer, der diese Funktion verwendet, benötigen wir lediglich, was die Funktion tut, welche Parameter sie benötigt und welche Funktionsausgabe erfolgt.
Python hat eine Funktionsdokumentation mithilfe von Docstring integriert. Hier ein Beispiel für eine Dokumentzeichenfolge.
def add(x, y): """Add two number Parameter:\n x -- int\n y -- int\n Return: int """ return x + y def send_email(sender, receiver, message): """Send email from sender to receiver Parameter:\n sender -- email sender, class User\n receiver -- email receiver, class User\n message -- body of the email, dictionary (ex: {"title": "some title", "body": "email body"}\n Return: None """ ...
Das Tolle an docstring ist, dass es mit dem Editor kompatibel ist. In vscode wird die Dokumentzeichenfolge angezeigt, wenn Sie mit der Maus über eine Funktion fahren. Die meisten Bibliotheken in Python verwenden Docstring, um ihre Funktion zu dokumentieren.
Das Problem mit docstring ist die Dokumentsynchronisierung. So stellen Sie sicher, dass die Dokumentzeichenfolge immer mit der Codeimplementierung synchronisiert wird. Man kann es nicht richtig auf die Probe stellen. Ich höre von einer zufälligen Person im Internet: „Veraltete Dokumentation zu haben ist schlimmer, als keine Dokumentation zu haben.“
Übrigens können Sie docstring irgendwie mit doctest testen. Doctest testet Ihren Dokumentstring, indem er ein Beispiel für Ihren Dokumentstring ausführt. Doctest ist in Python bereits vorinstalliert, sodass Sie keine externen Abhängigkeiten benötigen. Sehen wir uns dieses Beispiel an. Erstellen Sie eine neue Datei mit dem Namen my_math.py und geben Sie dann diesen Code ein.
# my_math.py def add(x, y): """Add two integer Parameter:\n x -- int\n y -- int\n Return: int >>> add(1, 2) 3 """ return x + y if __name__ == "__main__": import doctest doctest.testmod()
Es ist derselbe Code wie docstring example, aber ich füge in der letzten Zeile des Codes example und doctest hinzu. Um den Dokumentstring zu testen, führen Sie einfach die Datei python my_math.py aus. Wenn es keine Ausgabe gibt, bedeutet das, dass Ihr Beispiel den Test besteht. Wenn Sie die Ausgabe sehen möchten, führen Sie sie im ausführlichen Modus python my_math.py -v aus. Sie sehen diese Ausgabe.
Trying: add(1, 2) Expecting: 3 ok 1 items had no tests: __main__ 1 items passed all tests: 1 tests in __main__.add 1 tests in 2 items. 1 passed and 0 failed. Test passed
Wenn Sie im Codebeispiel einen Fehler machen, wird ein Fehler zurückgegeben.
# my_math.py def add(x, y): """Add two integer Parameter:\n x -- int\n y -- int\n Return: int >>> add(2, 2) # <-- I change it here 3 """ return x + y if __name__ == "__main__": import doctest doctest.testmod()
die Ausgabe:
********************************************************************** File "~/typescript-in-python/my_math.py", line 12, in __main__.add Failed example: add(2, 2) # <-- I change it here Expected: 3 Got: 4 ********************************************************************** 1 items had failures: 1 of 1 in __main__.add ***Test Failed*** 1 failures.
Großartig! Jetzt kann ich meinen Dokumentstring testen. Aber die Vorbehalte sind:
Manchmal müssen Sie den Code nicht ausführen, um zu überprüfen, ob der Code korrekt ist oder nicht. Sie benötigen lediglich den Eingabetyp und den Ausgabetyp. Wie? Betrachten Sie dieses Beispiel.
def add(x, y): """Add two integer Parameter:\n x -- int\n y -- int\n Return: int """ return x + y def sub(x, y): """Substract two integer Parameter:\n x -- int\n y -- int\n Return: int """ return x - y a = add(2, 1) b = add(1, 1) c = sub(a, b)
Funktion add gibt einen int zurück und function sub benötigt zwei int als Eingabeparameter. Wenn ich zwei Return from Add-Funktionen verwende und sie dann wie im obigen Beispiel auf einen Unterparameter füge, wird es einen Fehler geben? Natürlich nicht, weil die Unterfunktion ein int benötigt und Sie auch ein int eingeben.
Seit Python 3.5 verfügt Python über einen integrierten Typ namens Typing. Mit der Eingabe können Sie Ihrer Funktion wie im folgenden Beispiel einen Typ hinzufügen.
def add(x: int, y: int) -> int: """Add two integer""" return x + y a = add(1, 2)
Instead put it on your docstring you put it on the function. Typing is supported on many editor. If you use vscode you can hover on variable and it will shown it's type.
Nice now our code will have a type safety. eeehhhh not realy. If I intentionally use function incorrectlly like this.
def add(x: int, y: int) -> int: """Add two integer""" return x + y res = add(1, []) print(res)
It will show error
Traceback (most recent call last): File "~/typescript-in-python/main.py", line 5, in <module> res = add(1, []) ^^^^^^^^^^ File "~/typescript-in-python/main.py", line 3, in add return x + y ~~^~~ TypeError: unsupported operand type(s) for +: 'int' and 'list'
But it doesn't show that you put incorrect type. Even worse if you use it like this.
def add(x: int, y: int) -> int: """Add two integer""" return x + y res = add("hello", "world") print(res)
It will succeed. It must be error because you put incorrect type.
helloworld
Why python typing doesn't have type checker by default??. Based on pep-3107 it said
Before launching into a discussion of the precise ins and outs of Python 3.0’s function annotations, let’s first talk broadly about what annotations are and are not:
- Function annotations, both for parameters and return values, are completely optional.
- Function annotations are nothing more than a way of associating arbitrary Python expressions with various parts of a function at compile-time. By itself, Python does not attach any particular meaning or significance to annotations. Left to its own, Python simply makes these expressions available as described in Accessing Function Annotations below.
The only way that annotations take on meaning is when they are interpreted by third-party libraries. ...
So in python typing is like a decorator in typescript or java it doesn't mean anything. You need third party libraries todo type checking. Let's see some library for typechecking.
Here are libraries for typechecking in python. For example we will typecheck this wrong.py file
def add(x: int, y: int) -> int: """Add two integer""" return x + y res = add("hello", "world") print(res)
1.mypy
The "OG" of python type checker. To install it just using pip pip install mypy. Now let's use mypy to typecheck this file. Run mypy wrong.py. It will shown type error which is nice.
wrong.py:5: error: Argument 1 to "add" has incompatible type "str"; expected "int" [arg-type] wrong.py:5: error: Argument 2 to "add" has incompatible type "str"; expected "int" [arg-type] Found 2 errors in 1 file (checked 1 source file)
btw you can run mypy on entire project by using mypy ..
2.pyright
Another typechecker is pyright. It created by microsoft. It's same like mypy install through pip pip install pyright. Then run it pyright wrong.py. It will shown this error.
~/typescript-in-python/wrong.py ~/typescript-in-python/wrong.py:5:11 - error: Argument of type "Literal['hello']" cannot be assigned to parameter "x" of type "int" in function "add" "Literal['hello']" is incompatible with "int" (reportArgumentType) ~/typescript-in-python/wrong.py:5:20 - error: Argument of type "Literal['world']" cannot be assigned to parameter "y" of type "int" in function "add" "Literal['world']" is incompatible with "int" (reportArgumentType) 2 errors, 0 warnings, 0 informations
It said that it's more faster than mypy but I found that's not much diffrent. Maybe my code base it's to small. Also pyright implement more python standard than mypy you can see on https://microsoft.github.io/pyright/#/mypy-comparison. Personaly I prefer mypy than pyright because the error message were more readable.
3.pylyzer
Speaking of performance and speed another new python typechecker pylyzer. It's written in rust. You can install it through pip pip install pylyzer or through cargo (rust package manager) cargo install pylyzer --locked. Then run it pylyzer wrong.py. It will shown this error.
Start checking: wrong.py Found 2 errors: wrong.py Error[#2258]: File wrong.py, line 5, <module>.res 5 | res = add("hello", "world") : ------- : |- expected: Int : `- but found: {"hello"} TypeError: the type of add::x (the 1st argument) is mismatched Error[#2258]: File wrong.py, line 5, <module>.res 5 | res = add("hello", "world") : ------- : |- expected: Int : `- but found: {"world"} TypeError: the type of add::y (the 2nd argument) is mismatched
So far this is the most readable and beautiful error message. It's reminds me of rust compiler error. Speed, performance and most readable error message, I think I will choose to using pylyzer if the package already stable. The problem is at the time I write this blog, pylyzer still in beta. It can only typecheck your code base, it haven't support external depedencies.
Alright we successfully write python code like typescript (kinda). There is more way to using python typing module other than check simple type (str, int, bool etc). Maybe I will cover more advance type it in next blog. Maybe you guys have opinion about this, know better typechecker other then those 3, found other way to do typecheck in python or other. let me know on comment section below. As always Happy Coding.
Das obige ist der detaillierte Inhalt vonPython-Code wie Typescript schreiben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!