Nützliche Python-Tipps, die Sie noch nicht kennengelernt haben

Es wurden viele Artikel über interessante Python-Funktionen geschrieben. Sie sprechen über das Entpacken von Listen und Tupeln in Variablen, über die teilweise Anwendung von Funktionen und über das Arbeiten mit iterierbaren Objekten. Aber in Python steckt noch so viel mehr dahinter. Der Autor des Artikels, den wir heute übersetzen, sagt, er möchte über einige der von ihm verwendeten Python-Funktionen sprechen. Gleichzeitig ist ihm eine Beschreibung dieser Möglichkeiten, ähnlich der hier gegebenen, noch nicht begegnet. Möglicherweise haben Sie nirgendwo anders darüber gelesen.



Eingabe-String-Daten löschen


Die Aufgabe, die vom Benutzer eingegebenen Daten zu bereinigen, ist für fast jedes Programm relevant. Häufig kommt es bei dieser Eingabeverarbeitung darauf an, Zeichen in Groß- oder Kleinbuchstaben umzuwandeln. Manchmal können Daten mit einem regulären Ausdruck gelöscht werden. In Fällen, in denen die Aufgabe kompliziert ist, können Sie sie jedoch erfolgreicher lösen. Zum Beispiel - das:

user_input = "This\nstring has\tsome whitespaces...\r\n" character_map = {  ord('\n') : ' ',  ord('\t') : ' ',  ord('\r') : None } user_input.translate(character_map) # This string has some whitespaces... " 

Hier können Sie sehen, wie die Leerzeichen "\n" und "\t" durch reguläre Leerzeichen ersetzt werden und wie das Zeichen "\r" vollständig aus der Zeichenfolge entfernt wird. Dies ist ein einfaches Beispiel, aber wir können es erweitern, indem wir mithilfe des unicodedata Datenpakets und seiner Funktion unicodedata combining() große Tabellen für die Neuzuordnung von unicodedata erstellen. Auf diese Weise können Sie alle nicht benötigten Zeilen aus den Zeilen entfernen.

Iterator-Slices abrufen


Wenn Sie versuchen, einen Teil eines Iterators TypeError , tritt ein TypeError Fehler auf, der darauf hinweist, dass Sie das Generatorobjekt nicht abonnieren können. Dieses Problem kann jedoch gelöst werden:

 import itertools s = itertools.islice(range(50), 10, 20) # <itertools.islice object at 0x7f70fab88138> for val in s: ... 

Mit der Methode itertools.islice können itertools.islice ein islice Objekt erstellen, bei dem es sich um einen Iterator handelt, islice erforderlichen Elemente islice . Hierbei ist jedoch zu beachten, dass bei dieser Konstruktion alle Elemente des Generators bis zum Beginn des Slice und alle Elemente im islice Objekt verwendet werden.

Start des iterierbaren Objekts überspringen


Manchmal müssen Sie mit einer Datei arbeiten, die, wie Sie wissen, mit einer bestimmten Anzahl unnötiger Zeilen beginnt - wie z. B. Zeilen mit Kommentaren. Um diese Zeilen zu überspringen, können Sie erneut auf die itertools zurückgreifen:

 string_from_file = """ // Author: ... // License: ... // // Date: ... Actual content... """ import itertools for line in itertools.dropwhile(lambda line: line.startswith("//"), string_from_file.split("\n")): print(line) 

Dieser Code gibt nur Zeilen nach dem Kommentarblock zurück, der sich am Anfang der Datei befindet. Ein solcher Ansatz kann nützlich sein, wenn Sie nur Elemente (in unserem Fall Linien) am Anfang des iterierbaren Objekts verwerfen müssen, deren genaue Anzahl jedoch nicht bekannt ist.

Funktionen, die nur benannte Argumente (kwargs) unterstützen


Um es bei Verwendung einer bestimmten Funktion zu ermöglichen, dass nur benannte Argumente übergeben werden können, haben Sie folgende Möglichkeiten:

 def test(*, a, b): pass test("value for a", "value for b") # TypeError: test() takes 0 positional arguments... test(a="value", b="value 2") #   - ... 

Dies kann hilfreich sein, um die Verständlichkeit des Codes zu verbessern. Wie Sie sehen, können Sie unser Problem leicht lösen, indem Sie das Argument * vor der Liste der benannten Argumente verwenden. Hier können Sie natürlich auch Positionsargumente verwenden - wenn Sie diese vor das Argument * .

Erstellen von Objekten, die die with-Anweisung unterstützen


Jeder weiß zum Beispiel, wie man eine Datei öffnet oder wie man mit der with Anweisung eine Sperre setzt. Aber ist es möglich, den Sperrsteuerungsmechanismus unabhängig zu implementieren? Ja, das ist ganz real. Das Ausführungskontext-Verwaltungsprotokoll wird mit den Methoden __enter__ und __exit__ implementiert:

 class Connection: def __init__(self):  ... def __enter__(self):  #  ... def __exit__(self, type, value, traceback):  #  ... with Connection() as c: # __enter__() executes ... # conn.__exit__() executes 

Dies ist die gebräuchlichste Methode, um die Funktionen des Kontextmanagers in Python zu implementieren. Dasselbe kann jedoch einfacher durchgeführt werden:

 from contextlib import contextmanager @contextmanager def tag(name): print(f"<{name}>") yield print(f"</{name}>") with tag("h1"): print("This is Title.") 

Hier wird das Kontextverwaltungsprotokoll unter Verwendung des contextmanager Dekorators implementiert. Der erste Teil der tag Funktion (vor dem yield ) wird ausgeführt, wenn Sie den with Block eingeben. Dieser Block wird dann ausgeführt, und danach wird der Rest der tag Funktion ausgeführt.

Sparen Sie Speicher mit __slots__


Wenn Sie jemals Programme geschrieben haben, die eine wirklich große Anzahl von Instanzen einer bestimmten Klasse erstellen, stellen Sie möglicherweise fest, dass solche Programme unerwartet viel Speicher benötigen. Dies liegt daran, dass Python Wörterbücher verwendet, um die Attribute von Klasseninstanzen darzustellen. Dies hat eine gute Auswirkung auf die Leistung, ist jedoch in Bezug auf den Speicherverbrauch ineffizient. Normalerweise verursacht diese Funktion jedoch keine Probleme. Wenn Sie jedoch in einer ähnlichen Situation mit Speichermangel konfrontiert sind, können Sie versuchen, das Attribut __slots__ :

 class Person: __slots__ = ["first_name", "last_name", "phone"] def __init__(self, first_name, last_name, phone):  self.first_name = first_name  self.last_name = last_name  self.phone = phone 

Wenn wir hier das Attribut __slots__ deklarieren, verwendet Python ein kleines Array fester Größe zum Speichern der Attribute, kein Wörterbuch. Dadurch wird der für jede Instanz der Klasse erforderliche Arbeitsspeicher erheblich reduziert. Die Verwendung des Attributs __slots__ weist einige Nachteile auf. __slots__ wir es verwenden, können wir keine neuen Attribute deklarieren. Wir sind nur auf die Attribute beschränkt, die sich in __slots__ . Darüber hinaus können Klassen mit dem Attribut __slots__ keine Mehrfachvererbung verwenden.

CPU und Speichergrenzen


Wenn Sie das Programm nicht optimieren oder die Verwendung des Prozessors verbessern möchten, sondern lediglich eine strikte Beschränkung der verfügbaren Ressourcen festlegen möchten, können Sie die entsprechende Bibliothek verwenden:

 import signal import resource import os #     def time_exceeded(signo, frame): print("CPU exceeded...") raise SystemExit(1) def set_max_runtime(seconds): #   signal     soft, hard = resource.getrlimit(resource.RLIMIT_CPU) resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard)) signal.signal(signal.SIGXCPU, time_exceeded) #     def set_max_memory(size): soft, hard = resource.getrlimit(resource.RLIMIT_AS) resource.setrlimit(resource.RLIMIT_AS, (size, hard)) 

Dies zeigt die Begrenzung der Prozessorzeit und der Speichergröße. Um die Verwendung des Prozessors durch das Programm RLIMIT_CPU , ermitteln wir zunächst die Werte für nicht-harte (soft) und harte (hard) Limits für eine bestimmte Ressource ( RLIMIT_CPU ). Dann setzen wir das Limit unter Verwendung einer bestimmten Anzahl von Sekunden, die durch das Argument seconds und den zuvor erhaltenen harten Grenzwert angegeben wird. Danach registrieren wir den signal , der bei Überschreitung der dem Programm zugewiesenen Prozessorzeit den Exit-Vorgang einleitet. Im Falle des Gedächtnisses erhalten wir wieder Werte für nicht starre und harte Grenzen, wonach wir die Grenze unter Verwendung der setrlimit Methode setrlimit , an die wir die Größe der Beschränkung ( size ) und den zuvor erhaltenen Wert der harten Grenze übergeben.

Steuern, was aus dem Modul importiert werden kann und was nicht


Einige Sprachen verfügen über äußerst klare Exportmechanismen aus Modulen von Variablen, Methoden und Schnittstellen. Beispielsweise werden nur Entitäten nach Golang exportiert, deren Namen mit einem Großbuchstaben beginnen. In Python wird alles exportiert. Aber nur bis das Attribut __all__ :

 def foo(): pass def bar(): pass __all__ = ["bar"] 

Im obigen Beispiel wird nur die bar exportiert. Wenn Sie das Attribut __all__ leer lassen, wird überhaupt nichts aus dem Modul exportiert. Der Versuch, etwas aus einem solchen Modul zu importieren, löst einen AttributeError Fehler aus.

Vereinfachen Sie die Erstellung von Vergleichsoperatoren


Es gibt viele Vergleichsoperatoren. Zum Beispiel __lt__ , __le__ , __gt__ , __ge__ . Nur wenige Leute werden die Aussicht auf ihre Implementierung für eine bestimmte Klasse mögen. Gibt es eine Möglichkeit, diese langweilige Aufgabe zu vereinfachen? Ja, das können Sie - mit Hilfe des functools.total_ordering Dekorateurs:

 from functools import total_ordering @total_ordering class Number: def __init__(self, value):  self.value = value def __lt__(self, other):  return self.value < other.value def __eq__(self, other):  return self.value == other.value print(Number(20) > Number(3)) print(Number(1) < Number(5)) print(Number(15) >= Number(15)) print(Number(10) <= Number(2)) 

Der Dekorator functools.total_ordering hier verwendet, um das Implementieren der Reihenfolge von Klasseninstanzen zu vereinfachen. Um den Betrieb zu gewährleisten, müssen nur die Vergleichsoperatoren __lt__ und __eq__ . Dies ist das Minimum, das ein Dekorateur benötigt, um die verbleibenden Vergleichsoperatoren zu konstruieren.

Zusammenfassung


Das soll nicht heißen, dass alles, worüber ich hier sprach, in der täglichen Arbeit eines jeden Python-Programmierers absolut notwendig ist. Einige der hier vorgestellten Techniken können jedoch von Zeit zu Zeit sehr hilfreich sein. Sie sind außerdem in der Lage, die Lösung von Problemen zu vereinfachen, für deren übliche Lösung viel Code und ein hohes Maß an einheitlicher Arbeit erforderlich sein kann. Außerdem möchte ich darauf hinweisen, dass alles, was besprochen wurde, Teil der Python-Standardbibliothek ist. Um ehrlich zu sein, erscheinen einige dieser Funktionen der Standardbibliothek etwas unerwartet. Dies legt nahe, dass, wenn jemand etwas in Python implementieren möchte, das nicht ganz gewöhnlich erscheint, er zuerst in der Standardbibliothek stöbern sollte. Wenn Sie dort nicht sofort das finden, was Sie brauchen, lohnt es sich vielleicht wieder, sehr sorgfältig dort zu graben. Stimmt, wenn eine gründliche Suche nicht erfolgreich war, ist das, was Sie benötigen, höchstwahrscheinlich wirklich nicht vorhanden. Wenn ja, sollten Sie sich an Bibliotheken von Drittanbietern wenden. In ihnen ist es definitiv zu finden.

Sehr geehrte Leser! Kennen Sie Standard-Python-Funktionen, die auf den ersten Blick ungewöhnlich erscheinen und als "Standard" bezeichnet werden?


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


All Articles