Nützliche Python-Tipps, die Sie noch nie zuvor getroffen haben. Teil 2

Wir haben kürzlich eine Übersetzung des Materials veröffentlicht, die nützliche Tipps für Python-Programmierer enthält. Dieses Material hat eine Fortsetzung, auf die wir Sie heute aufmerksam machen.



Slice-Benennung mit der Slice-Funktion


Das Arbeiten mit den vielen Werten, die in Indizes angegeben sind, kann schnell zu einem Durcheinander führen - sowohl in Bezug auf die Unterstützung als auch in Bezug auf die Lesbarkeit des Codes. Eine Möglichkeit, die Situation zu verbessern, besteht darin, Konstanten für die durch Indizes angegebenen Werte zu verwenden. Es gibt jedoch eine bessere Möglichkeit, Qualitätscode zu schreiben:

#       ID First Name   Last Name line_record = "2    John Smith" ID = slice(0, 8) FIRST_NAME = slice(9, 21) LAST_NAME = slice(22, 27) name = f"{line_record[FIRST_NAME].strip()} {line_record[LAST_NAME].strip()}" # name == "John Smith" 

In diesem Beispiel können Sie sehen, dass wir die verwirrenden Indizes loswerden konnten, indem Sie den Slices mithilfe der slice Funktion Namen geben und diese Namen zum Abrufen der Fragmente der Zeichenfolge verwenden. .start .stop zum slice Objekt erhalten Sie mit den .start , .stop und .step .

Anfordern eines Passworts vom Benutzer während der Programmausführung


Für viele Befehlszeilentools oder Skripts sind ein Benutzername und ein Kennwort erforderlich. Wenn Sie ein solches Programm schreiben müssen, ist das getpass Modul möglicherweise getpass :

 import getpass user = getpass.getuser() password = getpass.getpass() #   ... 

Mit diesem sehr einfachen Paket können Sie das Kennwort eines Benutzers anfordern und einen Benutzernamen erhalten, indem Sie den Namen abrufen, unter dem er angemeldet ist. Bei der Arbeit mit Kennwörtern sollten Sie jedoch beachten, dass nicht alle Systeme das Ausblenden von Kennwörtern unterstützen. Python wird versuchen, Sie zu benachrichtigen. In diesem Fall wird in der Befehlszeile eine entsprechende Warnung angezeigt.

Enge Übereinstimmungen in Zeichenfolgen finden


Lassen Sie uns nun über eine etwas mysteriösere Funktion der Python-Standardbibliothek sprechen. Angenommen, Sie befinden sich in einer Situation, in der Sie mithilfe eines Konzepts wie Levenshtein distance nach Wörtern in der Liste suchen mussten, die wie eine bestimmte Eingabezeile aussehen. Dieses Problem kann mit dem difflib Modul gelöst werden.

 import difflib difflib.get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'], n=2) # returns ['apple', 'ape'] 

Die Methode difflib.get_close_matches nach den besten Übereinstimmungen, die „gut genug“ sind. Das erste Argument dieser Methode gibt die Suchzeichenfolge an, das zweite Argument gibt die Liste an, in der die Suche ausgeführt wird. Dieser Methode kann ein optionales Argument n , das die maximale Anzahl der zurückgegebenen Übereinstimmungen angibt. Diese Methode unterstützt auch den optionalen Grenzwert für benannte Argumente (standardmäßig ist er auf 0.6 ), mit dem Sie einen Schwellenwert für die Bewertung von Übereinstimmungen festlegen können.

Mit IP-Adressen arbeiten


Wenn Sie Python-Programme für die Arbeit mit dem Netzwerk schreiben müssen, bedeutet dies, dass das ipaddress Modul für Sie sehr nützlich sein kann. Eine Möglichkeit besteht darin, eine Liste von IP-Adressen aus einem Adressbereich zu generieren, der im CIDR-Format (Classless Inter-Domain Routing, Classless Addressing) angegeben ist.

 import ipaddress net = ipaddress.ip_network('74.125.227.0/29') #      IPv6 # IPv4Network('74.125.227.0/29') for addr in net:    print(addr) # 74.125.227.0 # 74.125.227.1 # 74.125.227.2 # 74.125.227.3 # ... 

Eine weitere nützliche Funktion dieses Moduls ist die Überprüfung der IP-Adresse auf Zugehörigkeit zu einem bestimmten Netzwerk:

 ip = ipaddress.ip_address("74.125.227.3") ip in net # True ip = ipaddress.ip_address("74.125.227.12") ip in net # False 

Das ipaddress Modul hat viele andere interessante Funktionen, über die ich hier nicht spreche. Lesen Sie hier mehr über ihn. Beachten Sie bei der Verwendung dieses Moduls die Einschränkungen hinsichtlich der Zusammenarbeit mit anderen Modulen im Zusammenhang mit der Netzwerkprogrammierung. Beispielsweise können Sie IPv4Network Instanzen nicht als Adresszeichenfolgen verwenden. Ähnliche Objekte müssen dazu erst mit str in Strings konvertiert werden.

Debuggen eines Programms in der Befehlszeile


Wenn Sie zu denjenigen gehören, die die IDE nicht verwenden möchten und Code in Vim oder Emacs schreiben, müssen Sie möglicherweise einen Debugger wie den in der IDE ausführen. Und weißt du was? Sie haben bereits einen solchen Debugger. Führen Sie dazu einfach das Programm mit einer Struktur wie python3.8 -i . Mit dem Flag -i kann nach Abschluss des Programms eine interaktive Shell gestartet werden. Damit können Sie Variablen untersuchen und Funktionen aufrufen. Dies ist eine interessante Funktion, aber was ist mit einem echten Debugger (PDB)? Experimentieren wir mit dem folgenden einfachen Programm, dessen Code in der Datei script.py enthalten ist:

 def func():    return 0 / 0 func() 

Führen Sie es mit dem python3.8 -i script.py und erhalten Sie Folgendes:

 #   ... Traceback (most recent call last):  File "script.py", line 4, in <module>    func()  File "script.py", line 2, in func    return 0 / 0 ZeroDivisionError: division by zero >>> import pdb >>> pdb.pm() #      > script.py(2)func() -> return 0 / 0 (Pdb) 

Wir sehen den Ort des Programms, an dem der Absturz aufgetreten ist. Legen Sie einen Haltepunkt fest:

 def func():    breakpoint() # import pdb; pdb.set_trace()    return 0 / 0 func() 

Führen Sie das Skript erneut aus.

script.py(3)func()
-> return 0 / 0
(Pdb) #
(Pdb) step
ZeroDivisionError: division by zero
> script.py(3)func()
-> return 0 / 0
(Pdb)

In den meisten Situationen reichen der Druckbefehl und die Trace-Ergebnisse zum Debuggen von Skripten aus. Manchmal müssen Sie sich jedoch mit dem Programm vertraut machen, um einen komplexen Fehler zu beheben. In solchen Fällen werden im Code Haltepunkte gesetzt und das Programm überprüft. Sie untersuchen zum Beispiel die Argumente von Funktionen, werten Ausdrücke aus, überprüfen die Werte von Variablen oder führen, wie oben gezeigt, einfach eine schrittweise Codeausführung durch. Pdb ist ein voll funktionsfähiger Python-Wrapper. In dieser Shell können Sie fast alles tun. Im Laufe der Arbeit werden sich einige spezielle Debugger-Befehle als nützlich erweisen, für die Sie hier Hilfe finden.

Mehrere Konstruktoren in einer Klasse deklarieren


Funktionsüberladung ist eine der Funktionen, die in verschiedenen Programmiersprachen weit verbreitet sind, jedoch nicht in Python. Und obwohl Sie eine reguläre Funktion in Python nicht überladen können, können Sie Konstruktoren mit Klassenmethoden überladen:

 import datetime class Date:    def __init__(self, year, month, day):        self.year = year        self.month = month        self.day = day    @classmethod    def today(cls):        t = datetime.datetime.now()        return cls(t.year, t.month, t.day) d = Date.today() print(f"{d.day}/{d.month}/{d.year}") # 14/9/2019 

In einer ähnlichen Situation könnten Sie versucht sein, anstelle von Klassenmethoden die gesamte Logik alternativer Konstruktoren in __init__ und das Problem mit *args , **kwargs und vielen if lösen. Das Ergebnis kann ein funktionierender Code sein, der jedoch schwer zu lesen und zu warten ist. Hier würde ich empfehlen, ein Minimum an Logik in __init__ und alle Operationen in separaten Methoden / Konstruktoren durchzuführen. Mit diesem Ansatz verfügen wir über einen sauberen Code, der sowohl für den Autor dieses Codes als auch für denjenigen, der diesen Code verwendet, von Vorteil ist.

Caching von Funktionsaufrufergebnissen mit einem Decorator


Haben Sie jemals Funktionen geschrieben, die langwierige Lese- / Schreibvorgänge oder eher langsame rekursive Berechnungen durchgeführt haben? Dachten Sie gleichzeitig, dass das Zwischenspeichern der Ergebnisse solche Funktionen nicht beeinträchtigen würde? Sie können die Ergebnisse eines Funktionsaufrufs mit dem lru_cache Dekorator aus dem functools Modul zwischenspeichern ( lru_cache functools :

 from functools import lru_cache import requests @lru_cache(maxsize=32) def get_with_cache(url):    try:        r = requests.get(url)        return r.text    except:        return "Not Found" for url in ["https://google.com/",            "https://martinheinz.dev/",            "https://reddit.com/",            "https://google.com/",            "https://dev.to/martinheinz",            "https://google.com/"]:    get_with_cache(url) print(get_with_cache.cache_info()) # CacheInfo(hits=2, misses=4, maxsize=32, currsize=4) 

In diesem Beispiel führen wir GET-Anforderungen aus, deren Ergebnisse zwischengespeichert werden (bis zu 32 Ergebnisse können zwischengespeichert werden). Hier können Sie sehen, dass wir mit der cache_info Methode Informationen über den Funktionscache cache_info . Der Dekorator gibt uns auch die Methode clear_cache , mit der clear_cache Cache clear_cache . An dieser Stelle möchte ich auch darauf hinweisen, dass das Caching nicht mit Funktionen verwendet werden kann, die Nebenwirkungen haben, oder mit Funktionen, die bei jedem Aufruf veränderbare Objekte erstellen.

Suchen nach Elementen, die am häufigsten im iterablen Objekt gefunden werden


In der Liste der Elemente zu stehen, die häufiger vorkommen als andere, ist eine sehr häufige Aufgabe. Sie können es beispielsweise mit der for Schleife und einem Wörterbuch lösen, das Informationen über die Anzahl identischer Elemente sammelt. Ein solcher Ansatz ist jedoch Zeitverschwendung. Tatsache ist, dass Sie solche Probleme mit der Counter Klasse aus dem collections Modul lösen können:

 from collections import Counter cheese = ["gouda", "brie", "feta", "cream cheese", "feta", "cheddar",          "parmesan", "parmesan", "cheddar", "mozzarella", "cheddar", "gouda",          "parmesan", "camembert", "emmental", "camembert", "parmesan"] cheese_count = Counter(cheese) print(cheese_count.most_common(3)) # : [('parmesan', 4), ('cheddar', 3), ('gouda', 2)] 

Die internen Mechanismen der Counter Klasse basieren auf einem Wörterbuch, in dem die Entsprechung der Elemente und die Anzahl der Einträge in der Liste gespeichert sind. Daher kann das entsprechende Objekt als reguläres dict werden:

 print(cheese_count["mozzarella"]) # : 1 cheese_count["mozzarella"] += 1 print(cheese_count["mozzarella"]) # : 2 

Darüber hinaus verfügen wir bei der Arbeit mit Counter über die Methode update(more_words) , mit der dem Counter neue Elemente hinzugefügt werden. Eine weitere nützliche Funktion von Counter ist, dass Sie mathematische Operationen (Addition und Subtraktion) verwenden können, wenn Sie mit Instanzen dieser Klasse arbeiten.

Zusammenfassung


Ich denke, dass die meisten der heute gegebenen Tipps von denen verwendet werden können, die fast täglich in Python schreiben. Ich hoffe, Sie finden unter ihnen etwas, das für Sie nützlich ist.

Sehr geehrte Leser! Kennen Sie interessante Python-Programmiertricks? Wenn ja, teilen Sie sie bitte.

Source: https://habr.com/ru/post/de485646/


All Articles