Kursinhalt
Optimierungstechniken in Python
Optimierungstechniken in Python
Messung der Funktionsleistung
Obwohl das Messen von stringbasierten Code-Snippets manchmal ausreichen mag, fehlt diesem Ansatz die Flexibilität. Die Verwendung von timeit
mit Funktionen bietet eine effektivere Möglichkeit, die Leistung zu messen, und Dekoratoren vereinfachen den Prozess der Messung der Leistung mehrerer Funktionen auf eine saubere und modulare Weise.
Verwendung von timeit mit Funktionen
timeit
kann die Leistung von Funktionen direkt messen, indem ein callable (d. h. eine Funktion) anstelle eines Strings übergeben wird. Dies ist flexibler und lesbarer als die Verwendung von Strings, insbesondere wenn Sie komplexe Funktionen benchmarken möchten.
import timeit import numpy as np # Function to test def generate_squares(): return np.array([x ** 2 for x in range(1000000)]) # Measure time using a callable (function) iterations = 15 execution_time = timeit.timeit(generate_squares, number=iterations) # Calculate average time per run average_time = execution_time / iterations print(f'Average execution time: {average_time:.6f} seconds')
Wir übergeben generate_squares
als die zu messende Funktion (callable) mit timeit.timeit()
. Ähnlich wie zuvor gibt der number
-Parameter an, wie oft die Funktion ausgeführt werden soll (15
Mal). Die durchschnittliche Ausführungszeit wird dann berechnet, indem die Gesamtzeit durch die Anzahl der Durchläufe geteilt wird.
Diese Methode ist sauberer und effizienter für das Benchmarking realer Funktionen und vermeidet den Overhead der Auswertung von Code aus einem String.
import timeit import numpy as np code_snippet = 'np.array([x ** 2 for x in range(1000000)])' iterations = 15 execution_time = timeit.timeit(code_snippet, number=iterations) average_time = execution_time / iterations print(f'Average execution time: {average_time:.6f} seconds')
Ups, wir haben den folgenden Fehler erhalten: NameError: name 'np' is not defined
. Der Fehler tritt auf, weil timeit.timeit()
den Code isoliert ausführt, sodass es keinen Zugriff auf numpy
hat, es sei denn, Sie importieren es explizit im setup
-Argument:
Die Verwendung von Funktionen ist sauberer, reduziert Fehler und erfordert nicht das Verwalten externer Importe über einen setup
-String.
Verbesserung der Leistungsbewertung mit Dekoratoren
Die Anwendung derselben Zeitmesslogik auf mehrere Funktionen ist eine gängige Praxis, und ein Dekorator bietet eine saubere und effiziente Möglichkeit, dies ohne Codewiederholung zu implementieren.
Jedes Mal, wenn eine Funktion aufgerufen wird, wird sie wie gewohnt ausgeführt, jedoch mit nahtlosem Benchmarking. Dekoratoren bieten mehrere Vorteile: Sie verbessern die Wiederverwendbarkeit, indem sie dieselbe Logik auf mehrere Funktionen anwenden, verbessern die Klarheit, indem sie die Zeitmesslogik von der Kernfunktionalität trennen, und ermöglichen Anpassungen, wie z.B. die Anpassung der Anzahl der Iterationen oder das Hinzufügen zusätzlicher Metriken zur Leistungsanalyse.
import timeit # Decorator to time the execution of a function def timeit_decorator(number=1): def decorator(func): def wrapper(*args, **kwargs): # Measure time with timeit total_time = timeit.timeit(lambda: func(*args, **kwargs), number=number) average_time = total_time / number print(f'{func.__name__} executed in {average_time:.6f} seconds (average over {number} runs)') return func(*args, **kwargs) return wrapper return decorator # Function to measure @timeit_decorator(number=30) def generate_squares(): return [x**2 for x in range(1000000)] # Calling the decorated function squares_array = generate_squares()
Jetzt, jedes Mal, wenn Sie eine Funktion aufrufen, die mit @timeit_decorator
dekoriert ist, wird ihre Leistung automatisch gemessen, und die Ergebnisse werden angezeigt.
Danke für Ihr Feedback!