py-funktion
Bild vom Autor

Wir alle schreiben Funktionen, wenn wir in Python programmieren. Aber schreiben wir unbedingt Intestine Funktionen? Nun, lasst es uns herausfinden.

Mit Funktionen in Python können Sie modularen Code schreiben. Wenn Sie eine Aufgabe haben, die Sie an mehreren Stellen ausführen müssen, können Sie die Logik der Aufgabe in eine Python-Funktion packen. Und Sie können die Funktion jedes Mal aufrufen, wenn Sie diese bestimmte Aufgabe ausführen müssen. So einfach der Einstieg in Python-Funktionen auch scheint, das Schreiben wartbarer und leistungsfähiger Funktionen ist nicht so einfach.

Aus diesem Grund werden wir einige Vorgehensweisen untersuchen, die Ihnen dabei helfen, sauberere und leicht zu wartende Python-Funktionen zu schreiben. Lassen Sie uns beginnen …

1. Schreiben Sie Funktionen, die nur eine Sache tun

Beim Schreiben von Funktionen in Python ist es oft verlockend, alle zugehörigen Aufgaben in einer einzigen Funktion zusammenzufassen. Dies kann Ihnen zwar dabei helfen, Dinge schnell zu programmieren, wird jedoch in naher Zukunft die Wartung Ihres Codes nur mühsam machen. Dies erschwert nicht nur das Verständnis dessen, was eine Funktion tut, sondern führt auch zu anderen Problemen, wie z. B. zu vielen Parametern (mehr dazu später!).

Als bewährte Vorgehensweise sollten Sie immer versuchen, Ihre Funktion nur eine Sache – eine Aufgabe – ausführen zu lassen und diese intestine zu machen. Aber manchmal müssen Sie für eine einzelne Aufgabe möglicherweise eine Reihe von Unteraufgaben abarbeiten. Wie entscheiden Sie additionally, ob und wie die Funktion umgestaltet werden soll?

Es hängt davon ab Was Anhand der Aufgaben, die die Funktion ausführen soll, und der Komplexität der Aufgabe können Sie die Trennung der Belange zwischen den Unteraufgaben erarbeiten. Und dann ermitteln Sie eine geeignete Ebene, auf der Sie die Funktion in mehrere Funktionen umgestalten können – wobei sich jede auf eine bestimmte Unteraufgabe konzentriert.

Refactoring-FunktionRefactoring-Funktion
Refactoring-Funktionen | Bild vom Autor

Hier ist ein Beispiel. Schauen Sie sich die Funktion an analyze_and_report_sales:

# fn. to investigate gross sales knowledge, calculate gross sales metrics, and write it to a file
def analyze_and_report_sales(knowledge, report_filename):
	total_sales = sum(merchandise('value') * merchandise('amount') for merchandise in knowledge)
	average_sales = total_sales / len(knowledge)
    
	with open(report_filename, 'w') as report_file:
    	    report_file.write(f"Whole Gross sales: {total_sales}n")
    	    report_file.write(f"Common Gross sales: {average_sales}n")
    
	return total_sales, average_sales

Es ist ganz einfach zu erkennen, dass es in zwei Funktionen umgestaltet werden kann: eine zum Berechnen der Verkaufskennzahlen und eine andere zum Schreiben der Verkaufskennzahlen in eine Datei wie folgt:

# refactored into two funcs: one to calculate metrics and one other to put in writing gross sales report
def calculate_sales_metrics(knowledge):
	total_sales = sum(merchandise('value') * merchandise('amount') for merchandise in knowledge)
	average_sales = total_sales / len(knowledge)
	return total_sales, average_sales

def write_sales_report(report_filename, total_sales, average_sales):
	with open(report_filename, 'w') as report_file:
    	    report_file.write(f"Whole Gross sales: {total_sales}n")
    	    report_file.write(f"Common Gross sales: {average_sales}n")

Jetzt ist es einfacher, Probleme mit der separaten Berechnung von Verkaufsmetriken und Dateivorgängen zu beheben. Und hier ist ein Beispiel für einen Funktionsaufruf:

knowledge = ({'value': 100, 'amount': 2}, {'value': 200, 'amount': 1})
total_sales, average_sales = calculate_sales_metrics(knowledge)
write_sales_report('sales_report.txt', total_sales, average_sales)

Sie sollten die Datei „sales_report.txt“ mit den Verkaufsmetriken in Ihrem Arbeitsverzeichnis sehen können. Dies ist ein einfaches Beispiel für den Einstieg, aber es ist besonders hilfreich, wenn Sie an komplexeren Funktionen arbeiten.

2. Fügen Sie Typhinweise hinzu, um die Wartbarkeit zu verbessern

Python ist eine dynamisch typisierte Sprache. Sie müssen additionally für die Variablen, die Sie erstellen, keine Typen deklarieren. Sie können jedoch Typhinweise hinzufügen, um den erwarteten Datentyp für Variablen anzugeben. Wenn Sie die Funktion definieren, können Sie die erwarteten Datentypen für die Parameter und die Rückgabewerte hinzufügen.

Da Python zur Laufzeit keine Typen erzwingt, hat das Hinzufügen von Typhinweisen zur Laufzeit keine Auswirkungen. Die Verwendung von Typhinweisen hat jedoch dennoch Vorteile, insbesondere im Hinblick auf die Wartbarkeit:

  • Das Hinzufügen von Typhinweisen zu Python-Funktionen dient als Inline-Dokumentation und vermittelt eine bessere Vorstellung davon, was die Funktion macht und welche Werte sie verbraucht und zurückgibt.
  • Wenn Sie Ihren Funktionen Typhinweise hinzufügen, können Sie Ihre IDE so konfigurieren, dass diese Typhinweise genutzt werden. So erhalten Sie hilfreiche Warnungen, wenn Sie versuchen, in einem oder mehreren Funktionsaufrufen ein Argument ungültigen Typs zu übergeben, Funktionen zu implementieren, deren Rückgabewerte nicht dem erwarteten Typ entsprechen, und dergleichen. So können Sie Fehler im Vorfeld minimieren.
  • Sie können non-compulsory statische Typprüfer verwenden wie meinPy um Fehler früher zu erkennen, anstatt zuzulassen, dass durch Typ-Inkonsistenzen subtile Bugs entstehen, die schwer zu debuggen sind.

Hier ist eine Funktion, die Bestelldetails verarbeitet:

# fn. to course of orders
def process_orders(orders):
	total_quantity = sum(order('amount') for order in orders)
	total_value = sum(order('amount') * order('value') for order in orders)
	return {
    	'total_quantity': total_quantity,
    	'total_value': total_value
	}

Fügen wir der Funktion nun Typhinweise wie folgt hinzu:

# modified with sort hints
from typing import Checklist, Dict

def process_orders(orders: Checklist(Dict(str, float | int))) -> Dict(str, float | int):
	total_quantity = sum(order('amount') for order in orders)
	total_value = sum(order('amount') * order('value') for order in orders)
	return {
    	'total_quantity': total_quantity,
    	'total_value': total_value
	}

Mit der modifizierten Model erfahren Sie, dass die Funktion eine Liste von Wörterbüchern aufnimmt. Die Schlüssel des Wörterbuchs sollten alle Zeichenfolgen sein und die Werte können entweder Ganzzahlen oder Gleitkommawerte sein. Die Funktion gibt auch ein Wörterbuch zurück. Sehen wir uns einen Beispielfunktionsaufruf an:

# Pattern knowledge
orders = (
	{'value': 100.0, 'amount': 2},
	{'value': 50.0, 'amount': 5},
	{'value': 150.0, 'amount': 1}
)

# Pattern perform name
consequence = process_orders(orders)
print(consequence)

Hier ist die Ausgabe:

{'total_quantity': 8, 'total_value': 600.0}

In diesem Beispiel helfen uns Typhinweise, eine bessere Vorstellung davon zu bekommen, wie die Funktion funktioniert. In Zukunft werden wir Typhinweise für alle besseren Versionen von Python-Funktionen hinzufügen, die wir schreiben.

3. Akzeptieren Sie nur die Argumente, die Sie wirklich brauchen

Wenn Sie Anfänger sind oder gerade Ihre erste Entwicklerrolle übernommen haben, ist es wichtig, beim Definieren der Funktionssignatur an die verschiedenen Parameter zu denken. Es ist durchaus üblich, zusätzliche Parameter in die Funktionssignatur einzuführen, die die Funktion nie wirklich verarbeitet.

Wenn sichergestellt wird, dass die Funktion nur die tatsächlich erforderlichen Argumente annimmt, bleiben Funktionsaufrufe insgesamt sauberer und wartungsfreundlicher. In einem ähnlichen Zusammenhang ist zu beachten, dass zu viele Parameter in der Funktionssignatur die Wartung ebenfalls erschweren. Wie additionally definieren Sie einfach zu wartende Funktionen mit der richtigen Anzahl von Parametern?

Wenn Sie eine Funktionssignatur mit einer wachsenden Anzahl von Parametern schreiben, besteht der erste Schritt darin, alle nicht verwendeten Parameter aus der Signatur zu entfernen. Wenn auch nach diesem Schritt zu viele Parameter vorhanden sind, gehen Sie zurück zu Tipp Nr. 1: Teilen Sie die Aufgabe in mehrere Unteraufgaben auf und refaktorisieren Sie die Funktion in mehrere kleinere Funktionen. Dies hilft dabei, die Anzahl der Parameter unter Kontrolle zu halten.

Anzahl ParameterAnzahl Parameter
Behalten Sie num_params unter Kontrolle | Bild vom Autor

Es ist Zeit für ein einfaches Beispiel. Hier enthält die Funktionsdefinition zur Berechnung der Schülernoten die teacher Parameter, der nie verwendet wird:

# takes in an arg that is by no means used!
def process_student_grades(student_id, grades, course_name, teacher'):
	average_grade = sum(grades) / len(grades)
	return f"Scholar {student_id} achieved a mean grade of {average_grade:.2f} in {course_name}."


Sie können die Funktion neu schreiben, ohne teacher Parameter wie folgt:

# higher model!
def process_student_grades(student_id: int, grades: record, course_name: str) -> str:
	average_grade = sum(grades) / len(grades)
	return f"Scholar {student_id} achieved a mean grade of {average_grade:.2f} in {course_name}."

# Utilization
student_id = 12345
grades = (85, 90, 75, 88, 92)
course_name = "Arithmetic"
consequence = process_student_grades(student_id, grades, course_name)
print(consequence)

Hier ist die Ausgabe des Funktionsaufrufs:

Scholar 12345 achieved a mean grade of 86.00 in Arithmetic.

4. Erzwingen Sie Nur-Schlüsselwort-Argumente, um Fehler zu minimieren

In der Praxis akzeptieren die meisten Python-Funktionen mehrere Argumente. Sie können Argumente an Python-Funktionen als Positionsargumente, Schlüsselwortargumente oder eine Mischung aus beidem übergeben. Lesen Sie Python-Funktionsargumente: Ein definitiver Leitfaden für eine schnelle Überprüfung der Funktionsargumente.

Einige Argumente sind von Natur aus positionell. Manchmal können Funktionsaufrufe, die nur positionelle Argumente enthalten, jedoch verwirrend sein. Dies gilt insbesondere dann, wenn die Funktion mehrere Argumente desselben Datentyps annimmt, von denen einige erforderlich und einige non-compulsory sind.

Wie Sie sich erinnern, werden bei Positionsargumenten die Argumente an die Parameter in der Funktionssignatur in der Dasselbe Reihenfolge, in der sie im Funktionsaufruf erscheinen. Änderungen in der Reihenfolge der Argumente können additionally zu subtilen Fehlern führen.

Es ist oft hilfreich, Non-compulsory Argumente Nur Schlüsselwort. Dadurch wird auch das Hinzufügen optionaler Parameter viel einfacher – ohne bestehende Aufrufe zu unterbrechen.

Hier ist ein Beispiel. Die process_payment Funktion nimmt eine optionale description Zeichenfolge:

# instance fn. for processing transaction
def process_payment(transaction_id: int, quantity: float, forex: str, description: str = None):
	print(f"Processing transaction {transaction_id}...")
	print(f"Quantity: {quantity} {forex}")
	if description:
    		print(f"Description: {description}")

Angenommen, Sie möchten die optionale description ein reines Schlüsselwortargument. So können Sie es machen:

# implement keyword-only arguments to reduce errors
# make the non-compulsory `description` arg keyword-only
def process_payment(transaction_id: int, quantity: float, forex: str, *, description: str = None):
	print(f"Processing transaction {transaction_id}:")
	print(f"Quantity: {quantity} {forex}")
	if description:
    		print(f"Description: {description}")

Betrachten wir einen Beispielfunktionsaufruf:

process_payment(1234, 100.0, 'USD', description='Cost for companies')

Dies gibt aus:

Processing transaction 1234...
Quantity: 100.0 USD
Description: Cost for companies

Versuchen Sie nun, alle Argumente als Positionsargumente zu übergeben:

# throws error as we attempt to go in additional positional args than allowed!
process_payment(5678, 150.0, 'EUR', 'Bill cost') 

Sie erhalten die folgende Fehlermeldung:

Traceback (most up-to-date name final):
  File "/house/balapriya/better-fns/tip4.py", line 9, in 
	process_payment(1234, 150.0, 'EUR', 'Bill cost')
TypeError: process_payment() takes 3 positional arguments however 4 got

5. Geben Sie keine Hear aus Funktionen zurück; verwenden Sie stattdessen Generatoren

Es ist durchaus üblich, Python-Funktionen zu schreiben, die Sequenzen wie z. B. eine Liste von Werten generieren. Sie sollten jedoch möglichst vermeiden, Hear von Python-Funktionen zurückzugeben. Stattdessen können Sie sie als Generatorfunktionen neu schreiben. Generatoren verwenden eine verzögerte Auswertung; sie liefern additionally Elemente der Sequenz bei Bedarf, anstatt alle Werte im Voraus zu berechnen. Lesen Sie Erste Schritte mit Python-Generatoren für eine Einführung in die Funktionsweise von Generatoren in Python.

Nehmen wir als Beispiel die folgende Funktion, die die Fibonacci-Folge bis zu einer bestimmten Obergrenze generiert:

# returns a listing of Fibonacci numbers
def generate_fibonacci_numbers_list(restrict):
	fibonacci_numbers = (0, 1)
	whereas fibonacci_numbers(-1) + fibonacci_numbers(-2) <= restrict:
    		fibonacci_numbers.append(fibonacci_numbers(-1) + fibonacci_numbers(-2))
	return fibonacci_numbers

Es handelt sich um eine rekursive Implementierung, die rechenintensiv ist und das Auffüllen und Zurückgeben der Liste erscheint ausführlicher als nötig. Hier ist eine verbesserte Model der Funktion, die Generatoren verwendet:

# use mills as an alternative
from typing import Generator

def generate_fibonacci_numbers(restrict: int) -> Generator(int, None, None):
	a, b = 0, 1
	whereas a <= restrict:
    		yield a
    	a, b = b, a + b

In diesem Fall gibt die Funktion ein Generatorobjekt zurück, das Sie dann durchlaufen können, um die Elemente der Sequenz zu erhalten:

restrict = 100
fibonacci_numbers_generator = generate_fibonacci_numbers(restrict)
for num in fibonacci_numbers_generator:
	print(num)

Hier ist die Ausgabe:

0
1
1
2
3
5
8
13
21
34
55
89

Wie Sie sehen, kann die Verwendung von Generatoren insbesondere bei großen Eingabegrößen viel effizienter sein. Außerdem können Sie mehrere Generatoren miteinander verketten, sodass Sie mit Generatoren effiziente Datenverarbeitungspipelines erstellen können.

Einpacken

Und das struggle’s. Den gesamten Code finden Sie auf GitHub. Hier ist eine Übersicht über die verschiedenen Tipps, die wir besprochen haben:

  • Schreiben Sie Funktionen, die nur eine Sache tun
  • Fügen Sie Typhinweise hinzu, um die Wartbarkeit zu verbessern
  • Akzeptieren Sie nur die Argumente, die Sie wirklich brauchen
  • Erzwingen Sie Argumente, die nur aus Schlüsselwörtern bestehen, um Fehler zu minimieren
  • Geben Sie keine Hear von Funktionen zurück; verwenden Sie stattdessen Generatoren

Ich hoffe, Sie fanden sie hilfreich! Wenn Sie diese Vorgehensweisen beim Schreiben von Python-Funktionen nicht bereits ausprobieren, sollten Sie sie ausprobieren. Viel Spaß beim Programmieren!

Bala Priya C ist Entwicklerin und technische Redakteurin aus Indien. Sie arbeitet gerne an der Schnittstelle zwischen Mathematik, Programmierung, Datenwissenschaft und Inhaltserstellung. Ihre Interessens- und Fachgebiete umfassen DevOps, Datenwissenschaft und natürliche Sprachverarbeitung. Sie liest, schreibt, programmiert und trinkt gerne Kaffee! Derzeit arbeitet sie daran, ihr Wissen zu lernen und mit der Entwickler-Group zu teilen, indem sie Tutorials, Anleitungen, Meinungsbeiträge und mehr verfasst. Bala erstellt auch ansprechende Ressourcenübersichten und Programmier-Tutorials.



Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert