Heim  >  Artikel  >  Backend-Entwicklung  >  So schreiben Sie effizienten Python-Code

So schreiben Sie effizienten Python-Code

巴扎黑
巴扎黑Original
2017-09-09 11:38:381375Durchsuche

Dieser Artikel stellt hauptsächlich vor und teilt, wie man effizienten und eleganten Python-Code schreibt. Freunde, die ihn benötigen, können darauf verweisen

Dieser Artikel ist teilweise aus dem Buch „Effective Python“ und „Python3 Cookbook“ entnommen. Es wurden jedoch auch Änderungen vorgenommen und das eigene Verständnis und die Anwendung bewährter Methoden des Autors hinzugefügt.

Der vollständige Text umfasst etwa 9956 Wörter und das Lesen kann 24 Minuten dauern.

Pythonisches Listenschneiden

list[start:end:step]

Wenn Sie mit dem Schneiden am Anfang der Liste beginnen, ignorieren Sie die 0 im Startbit, z als list[:4]

Wenn Sie bis zum Ende der Liste ausschneiden, ignorieren Sie die 0 im Endbit. Beispiel: list[3:]

Wenn Sie die Liste ausschneiden, wird dies der Fall sein kein Problem sein, selbst wenn der Start- oder Endindex die Grenze überschreitet

Durch das Listen-Slicing wird die ursprüngliche Liste nicht geändert. Wenn alle Indizes leer bleiben, wird eine Kopie der ursprünglichen Liste generiert

Listenverständnisse

Verwenden Sie Listenverständnisse, um map und filter

Verwenden Sie keine Listenverständnisse, die mehr als zwei Ausdrücke enthalten

Wenn viele Daten vorhanden sind, Listenverständnisse verbrauchen möglicherweise viel Speicher. Zu diesem Zeitpunkt wird empfohlen, den Generatorausdruck

Iteration

zu verwenden Index, verwenden Sie

enumerate

Sie können den zweiten Parameter als Wert akzeptieren, der zu enumerate hinzugefügt wird, wenn Sie index

verwenden

um zwei Iteratoren gleichzeitig zu durchlaufen zip

Gibt beim Durchlaufen ein Tupel zurückzip

Über

und forwhile Blöcke nach der Schleifeelse

Die Schleife

ruft den Code in auf, nachdem sie normal beendet wurdeelse

Wenn Sie

zum Unterbrechen verwenden Außerhalb der Schleife wird breakelse

nicht ausgeführt. Wenn die zu durchlaufende Sequenz leer ist, führen Sie sie sofort aus

else

Umgekehrte Iteration

Für gewöhnliche Sequenzen (Listen) können wir die integrierte Funktion

übergeben, die eine umgekehrte Iteration durchführt: reversed()

Darüber hinaus können Sie auch Führen Sie eine umgekehrte Iteration für die Klasse durch, indem Sie die Methode

in der Klasse implementieren: __reversed__

try/except/else/finally

Wenn innerhalb von

keine Ausnahme auftritt, Der Code in try wird else

in else aufgerufen. Vor dem Ausführen von finally

wird schließlich

ausgeführt, wo Sie die Funktion finally

bereinigen können verwendet einen Dekorator

Der Dekorator wird verwendet, um den ursprünglichen Funktionscode zu ändern, ohne ihn zu ändern. Ändern Sie eine vorhandene Funktion. Ein häufiges Szenario besteht darin, einen Debugging-Satz hinzuzufügen oder

Überwachunglog

zu einer vorhandenen Funktion hinzuzufügen. Zum Beispiel:

Darüber hinaus können Sie schreiben Sie auch: Der Dekorator, der Parameter empfängt, ist eigentlich eine Funktion, die in der äußeren Ebene des ursprünglichen Dekorators verschachtelt ist:

Bei der Verwendung des Dekorators wie oben gibt es jedoch ein Problem:

Mit anderen Worten, die ursprüngliche Funktion wurde im Decorator durch die Funktion

ersetzt. Der Aufruf einer dekorierten Funktion entspricht dem Aufruf einer neuen Funktion. Beim Anzeigen der Parameter, Kommentare und sogar Funktionsnamen der Originalfunktion werden nur Informationen angezeigt, die sich auf den Dekorator beziehen. Um dieses Problem zu lösen, können wir die new_fun

Python-eigene

-Methode verwenden. functools.wraps

ist eine sehr hackige Methode. Sie kann als Dekorator für die Funktion verwendet werden, die innerhalb des Dekorators zurückgegeben wird. Mit anderen Worten, es handelt sich um einen Dekorateur von Dekoratoren, der die ursprüngliche Funktion als Parameter verwendet. Seine Funktion besteht darin, verschiedene Informationen der ursprünglichen Funktion beizubehalten, sodass sie bei späterer Betrachtung der Informationen der dekorierten Originalfunktion genau erhalten bleiben können die gleiche wie die ursprüngliche funktion. functools.wraps

Darüber hinaus erledigt unser Dekorateur manchmal mehr als eine Aufgabe. In diesem Fall sollte die Veranstaltung als zusätzliche Funktion getrennt werden. Da es sich jedoch möglicherweise nur um den Dekorator handelt, kann zu diesem Zeitpunkt eine Dekoratorklasse erstellt werden. Das Prinzip ist sehr einfach, die Hauptsache ist, die Methode __call__ in die Klasse zu schreiben, damit die Klasse wie eine Funktion aufgerufen werden kann.

Verwenden Sie Generatoren

Erwägen Sie die Verwendung von Generatoren, um Funktionen neu zu schreiben, die Listen direkt zurückgeben

Bei dieser Methode gibt es mehrere kleine Probleme:

Jedes Mal, wenn ein Ergebnis erhalten wird, das die Bedingungen erfüllt, muss die Methode append aufgerufen werden. Tatsächlich liegt unser Fokus jedoch überhaupt nicht auf dieser Methode, sie ist lediglich ein Mittel für uns, um unser Ziel zu erreichen. Tatsächlich müssen wir nur index

Die zurückgegebenen result weiter optimieren

Die Daten werden in result gespeichert. Wenn die Datenmenge groß ist, wird sie mehr Speicher beanspruchen

Daher ist es besser, den Generator generator zu verwenden. Ein Generator ist eine Funktion, die einen yield-Ausdruck verwendet. Wenn der Generator aufgerufen wird, wird er nicht tatsächlich ausgeführt, sondern gibt einen Iterator zurück. Jedes Mal, wenn die integrierte next-Funktion für den Iterator aufgerufen wird Der Generator geht zum nächsten yield-Ausdruck über:

Nachdem Sie einen Generator erhalten haben, können Sie ihn normal durchlaufen:

Wenn Sie noch eine Liste benötigen, können Sie das Ergebnis des Funktionsaufrufs als Parameter verwenden und dann die listMethode

Iterierbares Objekt

aufrufen Es ist zu beachten, dass normale Iteratoren nur eine Runde lang iterieren können und wiederholte Aufrufe nach einer Runde ungültig sind. Der Weg, dieses Problem zu lösen, besteht darin, dass Sie eine iterierbare Containerklasse definieren können : Kein Problem:

Aber es sollte beachtet werden, dass es sich nur um eine handelt Iterator, der die

-Methode implementiert und nur durch die

-Schleife iteriert werden kann, wenn Sie übergeben möchten. Für die Methodeniteration müssen Sie die

-Methode verwenden:

__iter__fornextiterPositionsparameter verwenden

Manchmal ist die Anzahl der von der Methode empfangenen Parameter möglicherweise nicht sicher, z. B. Definieren Sie eine Summierungsmethode, die mindestens zwei Parameter empfangen muss:

Für diese Art von Funktion, die nicht unbedingt eine bestimmte Anzahl von Parametern hat und sich nicht um die Reihenfolge kümmert, in der die Parameter übergeben werden, sollten Sie Positionsparameter

:

Allerdings ist zu beachten, dass der Parameter variabler Länge *args bei der Übergabe an die Funktion zunächst in ein Tupel

umgewandelt werden muss. Das heißt, wenn Sie einen Generator als Parameter an eine Funktion übergeben, wird der Generator zuerst durchlaufen und in ein Tupel umgewandelt. Dies kann viel Speicher verbrauchen:

argsSchlüsselwortargumente verwenden tuple

Schlüsselwortargumente verbessern die Lesbarkeit des Codes

Kann den Schlüsselwortparametern übergeben werden Geben Sie Standardwerte für Funktionen an

, um die Erweiterung von Funktionsparametern zu erleichtern

Definieren Sie Funktionen, die nur Schlüsselwortparameter verwenden können

Auf die übliche Weise , beim Aufruf Die Verwendung von Schlüsselwortparametern wird nicht erzwungen, wenn

Die Methode zum Erzwingen von Schlüsselwortparametern in

Python3

Verwenden Sie die Methode zum Erzwingen von Schlüsselwortparametern in Python2

Über die Standardwerte von ParameternEs ist ein Klischee:

Der Standardwert einer Funktion wird nur einmal festgelegt, wenn das Programm das Modul lädt und die Definition der Funktion liest

Mit anderen Worten, wenn es sich um einen dynamischen Wert handelt einem Parameter zugewiesen wird (

Zum Beispiel

oder ), wenn den Parametern beim späteren Aufruf der Funktion andere Parameter zugewiesen werden, wenn diese Funktion in Zukunft erneut aufgerufen wird, die zuvor definierten Der Standardwert ändert sich und wird zum beim letzten Aufruf zugewiesenen Wert:

Daher wird eher empfohlen, None als Standardparameter zu verwenden und den Wert nach der Beurteilung innerhalb der Funktion zuzuweisen:

Klasse__slots__

Standardmäßig verwendet Python ein Wörterbuch, um die Instanzattribute eines Objekts zu speichern. Dadurch können wir zur Laufzeit dynamisch neue Attribute zu Klasseninstanzen hinzufügen:

Dieses Wörterbuch verschwendet jedoch zusätzlichen Platz – oft werden wir es nicht erstellen. So viele Attribute. Mit __slots__ können Sie Python

also anweisen, kein Wörterbuch, sondern eine feste Sammlung zum Zuweisen von Speicherplatz zu verwenden.

__call__

Durch die Definition der __call__-Methode in einer Klasse können Instanzen der Klasse wie gewöhnliche Funktionen aufgerufen werden.

Der Vorteil der Implementierung dieser Methode besteht darin, dass der Status über die Eigenschaften der Klasse gespeichert werden kann, ohne dass ein Abschluss oder eine globale Variable erstellt werden muss.

@classmethod & @staticmethod

@classmethod ist @staticmethod sehr ähnlich, ihre Verwendungsszenarien sind jedoch unterschiedlich.

Gewöhnliche Methoden innerhalb der Klasse verwenden alle self als ersten Parameter, was bedeutet, dass beim Aufruf über eine Instanz der Gültigkeitsbereich der Instanz an die Methode

@classmethod übergeben wird Die Verwendung von cls als ersten Parameter bedeutet, dass der Gültigkeitsbereich der Klasse selbst übergeben wird. Unabhängig davon, ob über eine Klasse oder eine Instanz einer Klasse aufgerufen wird, ist der erste standardmäßig übergebene Parameter die Klasse selbst

@staticmethodEs ist nicht erforderlich, Standardparameter zu übergeben, ähnlich wie bei einer gewöhnlichen Funktion

Lassen Sie uns ihre Nutzungsszenarien anhand von Beispielen kennenlernen:

Angenommen, wir müssen eine Klasse mit dem Namen Date erstellen, um drei Daten für Jahr/Monat/Tag zu speichern

Der obige Code erstellt die Date-Klasse, die das day/month/year-Attribut während der Initialisierung festlegt, und legt ein property bis getter fest, das über time instanziiert werden kann. Holen Sie sich die gespeicherte Zeit:

Aber was ist, wenn wir die Art und Weise ändern möchten, wie die Eigenschaften übergeben werden? Schließlich ist es ärgerlich, bei der Initialisierung die drei Attribute Jahr/Monat/Tag übergeben zu müssen. Können Sie eine Möglichkeit finden, eine Instanz von 2016-11-09 zu erstellen, indem Sie eine Zeichenfolge wie Date übergeben, ohne die vorhandene Schnittstelle und die vorhandenen Methoden zu ändern?

Sie könnten sich eine Methode wie diese vorstellen:

Aber sie ist nicht gut genug:

Schreiben Sie eine zusätzliche Methode außerhalb der Klasse. Jedes Mal müssen Sie die Parameter formatieren und dann abrufen.

Diese Methode bezieht sich nur auf die Date-Klasse.

löst nicht das Problem, dass zu viele Parameter in

Sie können es zu diesem Zeitpunkt verwenden

, eine neue Formatzeichenfolge innerhalb der Klasse erstellen und die Methode der Klasseninstanz zurückgeben: @classmethod

Auf diese Weise haben wir kann es über die Klasse

aufrufen. Die Methode Date erstellt eine Instanz und greift nicht in die alte Instanziierungsmethode ein oder ändert sie nicht: from_string

Vorteile:

Innerhalb von

können Sie @classmethodParameter übergeben und so den gleichen Komfort wie beim externen Aufrufen von Klassen erhaltencls

Sie können die Methode darin weiter kapseln, um die Wiederverwendbarkeit zu verbessern

Eher im Einklang mit Objektorientierte Programmierung

Und

, da es einer gewöhnlichen Funktion ähnelt, können Sie die Hilfsmethode @staticmethod

, die sich auf diese Klasse bezieht, als

in die Klasse einfügen und dann Rufen Sie diese Methode direkt über die Klasse auf. @staticmethod

Nachdem datumsbezogene Hilfsklassenfunktionen als

-Methoden innerhalb der Klasse @staticmethod platziert wurden, können diese Methoden über die Klasse aufgerufen werden: Date

Erstellen Sie einen Kontextmanager

Kontextmanager, die beliebte Einführung ist: Bevor der Codeblock ausgeführt wird, erfolgt zuerst die Vorbereitungsarbeit, nach der Ausführung des Codeblocks erfolgt die Fertigstellung Arbeit ist erledigt Bearbeitungsarbeit. Die

-Anweisung erscheint häufig zusammen mit dem Kontextmanager. Zu den klassischen Szenarios gehören: with

Durch die with-Anweisung schließt der Code den Dateiöffnungsvorgang ab und schließt die Datei automatisch, wenn der Aufruf endet oder während des Lesens eine Ausnahme auftritt, dh die Verarbeitung nach dem Lesen und Das Schreiben der Datei ist abgeschlossen. Wenn Sie den Kontextmanager nicht übergeben, sieht der Code wie folgt aus:

Ist das nicht umständlicher? Der Vorteil der Verwendung des Kontextmanagers besteht also darin, dass er uns automatisch dabei hilft, die Arbeit zu erledigen, wenn die Ausführung des Codeblocks beginnt und endet, indem er unsere voreingestellten Rückrufe aufruft. Mit den Methoden __enter__ und __exit__ der benutzerdefinierten Klasse können wir einen Kontextmanager anpassen.

kann dann so aufgerufen werden:

Beim Aufruf:

Das with Die Anweisung speichert zunächst vorübergehend die ReadFile-Methode __exit__

der

-Klasse und ruft dann die ReadFile-Methode __enter__ der

-Klasse

__enter__with-Methode zum Öffnen auf die Datei und speichert das Ergebnis. Zurück zur

-Anweisung

file_read wird das Ergebnis des vorherigen Schritts an den

-Parameter übergeben.

with bearbeitet den file_read-Parameter innerhalb von

-Anweisung und liest jede Zeile

withNachdem der Lesevorgang abgeschlossen ist, ruft die __exit__-Anweisung die zuvor gespeicherte

-Methode

__exit__

auf, um die Datei zu schließen

__exit__Es ist zu beachten, dass wir in der True-Methode Inside die Datei schließen, aber am Ende with zurückgeben, sodass der Fehler nicht durch die with-Anweisung ausgelöst wird. Andernfalls löst die

-Anweisung einen entsprechenden Fehler aus.

Das obige ist der detaillierte Inhalt vonSo schreiben Sie effizienten Python-Code. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn