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)
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)
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")
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):
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
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?
