

Bild von Autor | Ideogramm
Seien wir ehrlich. Wenn Sie Python lernen, denken Sie wahrscheinlich nicht über Leistung nach. Sie versuchen nur, Ihren Code zum Laufen zu bringen! Aber hier ist die Sache: Wenn Sie Ihren Python -Code schneller machen, müssen Sie über Nacht kein Expertenprogrammierer werden.
Mit ein paar einfachen Techniken, die ich Ihnen heute zeigen werde, können Sie die Geschwindigkeits- und Speicherverbrauch Ihres Codes erheblich verbessern.
In diesem Artikel werden wir zusammen fünf praktische anfängerfreundliche Optimierungstechniken durchlaufen. Für jeden zeige ich Ihnen den Code „vor“ (die Artwork und Weise, wie viele Anfänger ihn schreiben), den „After“ -Code (die optimierte Model) und erklären genau, warum die Verbesserung funktioniert und wie viel schneller es wird.
🔗 Hyperlink zum Code auf GitHub
1. Ersetzen Sie Schleifen durch Listenverständnisse
Beginnen wir mit etwas, das Sie wahrscheinlich die ganze Zeit tun: Erstellen neuer Hear, indem Sie vorhandene transformieren. Die meisten Anfänger greifen nach einer für die Schleife, aber Python hat eine viel schnellere Möglichkeit, dies zu tun.
Vor der Optimierung
Hier erfahren Sie, wie die meisten Anfänger eine Liste von Zahlen quadrieren würden:
import time
def square_numbers_loop(numbers):
end result = ()
for num in numbers:
end result.append(num ** 2)
return end result
# Let's check this with 1000000 numbers to see the efficiency
test_numbers = record(vary(1000000))
start_time = time.time()
squared_loop = square_numbers_loop(test_numbers)
loop_time = time.time() - start_time
print(f"Loop time: {loop_time:.4f} seconds")
Dieser Code erstellt eine leere Liste namens Ergebnis, schaltet dann jede Nummer in unserer Eingabediste durch, quadriert sie und findet sie an die Ergebnisliste an. Ziemlich einfach, oder?
Nach der Optimierung
Schreiben wir dies nun mit einem Listenverständnis um:
def square_numbers_comprehension(numbers):
return (num ** 2 for num in numbers) # Create the whole record in a single line
start_time = time.time()
squared_comprehension = square_numbers_comprehension(test_numbers)
comprehension_time = time.time() - start_time
print(f"Comprehension time: {comprehension_time:.4f} seconds")
print(f"Enchancment: {loop_time / comprehension_time:.2f}x sooner")
Diese einzelne Zeile (num ** 2 for num in numbers) tut genau dasselbe wie unsere Schleife, aber es sagt Python: „Erstellen Sie eine Liste, in der jedes Factor das Quadrat des entsprechenden Parts in Zahlen ist.“
Ausgabe:
Loop time: 0.0840 seconds
Comprehension time: 0.0736 seconds
Enchancment: 1.14x sooner
Leistungsverbesserung: Listenverständnisse sind typischerweise 30-50% schneller als äquivalente Schleifen. Die Verbesserung macht sich deutlicher, wenn Sie mit sehr großen iterablen arbeiten.
Warum funktioniert das? Listenverständnisse werden in C unter der Motorhaube implementiert, sodass sie einen Großteil des Overheads vermeiden, das mit Python -Schleifen geliefert wird, Dinge wie variable Lookups und Funktionsaufrufe hinter den Kulissen.
2. Wählen Sie die richtige Datenstruktur für den Job aus
Das ist riesig und es ist etwas, das Ihren Code hundert Male mit nur einer kleinen Änderung schneller machen kann. Der Schlüssel besteht darin, zu verstehen, wann Hear gegen Units gegen Wörterbücher verwendet werden sollen.
Vor der Optimierung
Angenommen, Sie möchten gemeinsame Elemente zwischen zwei Hear finden. Hier ist der intuitive Ansatz:
def find_common_elements_list(list1, list2):
frequent = ()
for merchandise in list1: # Undergo every merchandise within the first record
if merchandise in list2: # Verify if it exists within the second record
frequent.append(merchandise) # If sure, add it to our frequent record
return frequent
# Take a look at with moderately giant lists
large_list1 = record(vary(10000))
large_list2 = record(vary(5000, 15000))
start_time = time.time()
common_list = find_common_elements_list(large_list1, large_list2)
list_time = time.time() - start_time
print(f"Record strategy time: {list_time:.4f} seconds")
Dieser Code überlastet die erste Liste und für jedes Factor überprüft es, ob dieses Factor in der zweiten Liste verwendet wird. list2. Das Downside? Wenn Sie Gegenstand machen list2Python muss die gesamte zweite Liste durchsuchen, bis es den Artikel findet. Das ist langsam!
Nach der Optimierung
Hier ist die gleiche Logik, aber mit einem Set für schnellere Lookups:
def find_common_elements_set(list1, list2):
set2 = set(list2) # Convert record to a set (one-time price)
return (merchandise for merchandise in list1 if merchandise in set2) # Verify membership in set
start_time = time.time()
common_set = find_common_elements_set(large_list1, large_list2)
set_time = time.time() - start_time
print(f"Set strategy time: {set_time:.4f} seconds")
print(f"Enchancment: {list_time / set_time:.2f}x sooner")
Zunächst konvertieren wir die Liste in einen Satz. Dann anstatt zu überprüfen, ob Itsel in Artikel in list2Wir überprüfen, ob Artikel in set2. Diese winzige Veränderung macht die Mitgliedertests nahezu augenblicklich.
Ausgabe:
Record strategy time: 0.8478 seconds
Set strategy time: 0.0010 seconds
Enchancment: 863.53x sooner
Leistungsverbesserung: Dies kann für große Datensätze in der Reihenfolge von 100x schneller sein.
Warum funktioniert das? Units verwenden Hash -Tabellen unter der Motorhaube. Wenn Sie überprüfen, ob sich ein Factor in einem Satz befindet, durchsucht Python nicht jedes Factor. Es verwendet den Hash, um direkt dorthin zu springen, wo sich der Artikel befinden soll. Es ist, als würde man einen Index eines Buches haben, anstatt jede Seite zu lesen, um zu finden, was Sie wollen.
3. Verwenden Sie die integrierten Funktionen von Python, wann immer möglich
Python verfügt über unzählige eingebaute Funktionen, die stark optimiert sind. Bevor Sie Ihre eigene Schleife oder benutzerdefinierte Funktion schreiben, um etwas zu tun, prüfen Sie, ob Python bereits eine Funktion dafür hat.
Vor der Optimierung
So berechnen Sie möglicherweise die Summe und das Most einer Liste, wenn Sie nichts über integrierte Ins wussten:
def calculate_sum_manual(numbers):
whole = 0
for num in numbers:
whole += num
return whole
def find_max_manual(numbers):
max_val = numbers(0)
for num in numbers(1:):
if num > max_val:
max_val = num
return max_val
test_numbers = record(vary(1000000))
start_time = time.time()
manual_sum = calculate_sum_manual(test_numbers)
manual_max = find_max_manual(test_numbers)
manual_time = time.time() - start_time
print(f"Handbook strategy time: {manual_time:.4f} seconds")
Der sum Die Funktion beginnt mit insgesamt 0 und fügt dann jede Zahl dieser Gesamtsumme hinzu. Der max Die Funktion beginnt mit der Annahme, dass die erste Zahl maximal ist, und vergleicht dann jede andere Zahl, um festzustellen, ob sie größer ist.
Nach der Optimierung
Hier ist dasselbe mit den integrierten Funktionen von Python:
start_time = time.time()
builtin_sum = sum(test_numbers)
builtin_max = max(test_numbers)
builtin_time = time.time() - start_time
print(f"Constructed-in strategy time: {builtin_time:.4f} seconds")
print(f"Enchancment: {manual_time / builtin_time:.2f}x sooner")
Das battle’s! sum() gibt die Gesamtsumme aller Zahlen in der Liste an, und max() Gibt die größte Zahl zurück. Gleiches Ergebnis, viel schneller.
Ausgabe:
Handbook strategy time: 0.0805 seconds
Constructed-in strategy time: 0.0413 seconds
Enchancment: 1.95x sooner
Leistungsverbesserung: Eingebaute Funktionen sind in der Regel schneller als manuelle Implementierungen.
Warum funktioniert das? Die integrierten Funktionen von Python sind in C geschrieben und stark optimiert.
4. Führen Sie effiziente String -Vorgänge mit Be a part of durch
String -Verkettung ist etwas, was jeder Programmierer tut, aber die meisten Anfänger tun dies auf eine Weise, die exponentiell langsamer wird, wenn die Saiten länger werden.
Vor der Optimierung
So können Sie eine CSV -Zeichenfolge erstellen, indem Sie mit dem + Operator verkettet werden:
def create_csv_plus(knowledge):
end result = "" # Begin with an empty string
for row in knowledge: # Undergo every row of information
for i, merchandise in enumerate(row): # Undergo every merchandise within the row
end result += str(merchandise) # Add the merchandise to our end result string
if i < len(row) - 1: # If it is not the final merchandise
end result += "," # Add a comma
end result += "n" # Add a newline after every row
return end result
# Take a look at knowledge: 1000 rows with 10 columns every
test_data = ((f"item_{i}_{j}" for j in vary(10)) for i in vary(1000))
start_time = time.time()
csv_plus = create_csv_plus(test_data)
plus_time = time.time() - start_time
print(f"String concatenation time: {plus_time:.4f} seconds")
Dieser Code erstellt unser CSV -Zeichenfolge Stück für Stück. Für jede Zeile geht es in jedem Factor durch, konvertiert sie in eine Zeichenfolge und fügt es zu unserem Ergebnis hinzu. Es fügt Kommas zwischen Gegenständen und neuen Zeilen zwischen Zeilen hinzu.
Nach der Optimierung
Hier ist der gleiche Code mit der Be a part of -Methode:
def create_csv_join(knowledge):
# For every row, be part of the gadgets with commas, then be part of all rows with newlines
return "n".be part of(",".be part of(str(merchandise) for merchandise in row) for row in knowledge)
start_time = time.time()
csv_join = create_csv_join(test_data)
join_time = time.time() - start_time
print(f"Be a part of technique time: {join_time:.4f} seconds")
print(f"Enchancment: {plus_time / join_time:.2f}x sooner")
Diese einzelne Linie macht viel! Der innere Teil ",".be part of(str(merchandise) for merchandise in row) Nimmt jede Reihe und verbindet alle Gegenstände mit Kommas. Der äußere Teil "n".be part of(...) Nimmt all diese von Kommas getrennten Zeilen und schließt sich ihnen mit Newlines an.
Ausgabe:
String concatenation time: 0.0043 seconds
Be a part of technique time: 0.0022 seconds
Enchancment: 1.94x sooner
Leistungsverbesserung: String -Becoming a member of ist viel schneller als die Verkettung für große Saiten.
Warum funktioniert das? Wenn Sie += für die Verkettung von Zeichenfolgen verwenden, erstellt Python jedes Mal ein neues String -Objekt, da Zeichenfolgen unveränderlich sind. Bei großen Saiten wird dies unglaublich verschwenderisch. Der be part of Methode findet genau heraus, wie viel Speicher es im Voraus benötigt und die Zeichenfolge einmal erstellt.
5. Generatoren für die speichereffiziente Verarbeitung verwenden
Manchmal müssen Sie nicht alle Daten gleichzeitig im Speicher speichern. Mit Generatoren können Sie Daten on-Demand erstellen, die huge Mengen an Speicher sparen können.
Vor der Optimierung
So können Sie einen großen Datensatz verarbeiten, indem Sie alles in einer Liste speichern:
import sys
def process_large_dataset_list(n):
processed_data = ()
for i in vary(n):
# Simulate some knowledge processing
processed_value = i ** 2 + i * 3 + 42
processed_data.append(processed_value) # Retailer every processed worth
return processed_data
# Take a look at with 100,000 gadgets
n = 100000
list_result = process_large_dataset_list(n)
list_memory = sys.getsizeof(list_result)
print(f"Record reminiscence utilization: {list_memory:,} bytes")
Diese Funktion verarbeitet Zahlen von 0 bis n-1, wendet eine gewisse Berechnung auf jeden an (Quadrieren, multiplizieren Sie sie mit 3 und addieren 42) und speichert alle Ergebnisse in einer Liste. Das Downside ist, dass wir alle 100.000 verarbeiteten Werte gleichzeitig im Speicher halten.
Nach der Optimierung
Hier ist die gleiche Verarbeitung mit einem Generator:
def process_large_dataset_generator(n):
for i in vary(n):
# Simulate some knowledge processing
processed_value = i ** 2 + i * 3 + 42
yield processed_value # Yield every worth as an alternative of storing it
# Create the generator (this does not course of something but!)
gen_result = process_large_dataset_generator(n)
gen_memory = sys.getsizeof(gen_result)
print(f"Generator reminiscence utilization: {gen_memory:,} bytes")
print(f"Reminiscence enchancment: {list_memory / gen_memory:.0f}x much less reminiscence")
# Now we are able to course of gadgets one by one
whole = 0
for worth in process_large_dataset_generator(n):
whole += worth
# Every worth is processed on-demand and could be rubbish collected
Der Hauptunterschied ist yield anstatt append. Der yield Das Schlüsselwort macht dies zu einer Generatorfunktion – es erzeugt nacheinander Werte, anstatt sie alle gleichzeitig zu erstellen.
Ausgabe:
Record reminiscence utilization: 800,984 bytes
Generator reminiscence utilization: 224 bytes
Reminiscence enchancment: 3576x much less reminiscence
Leistungsverbesserung: Generatoren können „viel“ weniger Speicher für große Datensätze verwenden.
Warum funktioniert das? Generatoren verwenden eine faule Bewertung, sie berechnen nur Werte, wenn Sie nach ihnen fragen. Das Generatorobjekt selbst ist winzig; Es erinnert sich nur, wo es in der Berechnung ist.
Abschluss
Die Optimierung von Python -Code muss nicht einschüchternd sein. Wie wir gesehen haben, können kleine Veränderungen bei der Annäherung an gemeinsame Programmieraufgaben dramatische Verbesserungen sowohl bei der Geschwindigkeit als auch bei Speicherverbrauch führen. Der Schlüssel ist die Entwicklung einer Instinct für die Auswahl des richtigen Instruments für jeden Job.
Denken Sie an diese Kernprinzipien: Verwenden Sie integrierte Funktionen, wenn sie existieren, wählen Sie geeignete Datenstrukturen für Ihren Anwendungsfall, vermeiden Sie unnötige wiederholte Arbeiten und achten Sie darauf, wie Python das Gedächtnis umgeht. Hear Sie die Verständnisse, Units für Mitgliedsentests, String -Verbindungen, Generatoren für große Datensätze alle Instruments, die sich in jedem Anfängerpython -Programmierer -Toolkit befinden sollten. Lernen Sie weiter, kodieren Sie weiter!
Bala Priya c ist ein Entwickler und technischer Schriftsteller aus Indien. Sie arbeitet gern an der Schnittstelle zwischen Mathematik, Programmierung, Datenwissenschaft und Inhaltserstellung. Ihre Interessensgebiete und Fachgebiete umfassen DevOps, Knowledge Science und natürliche Sprachverarbeitung. Sie liest gerne, schreibt, codieren und Kaffee! Derzeit arbeitet sie daran, ihr Wissen mit der Entwicklergemeinschaft zu lernen und zu teilen, indem sie Tutorials, Anleitungen, Meinungsstücke und vieles mehr autorisiert. Bala erstellt auch ansprechende Ressourcenübersichten und Codierungs -Tutorials.
