Python & AI Tutorials Logo
Python Programmierung

20. Funktionsparameter und Argumente

In Kapitel 19 haben wir gelernt, wie man Funktionen(function) mit grundlegenden Parametern definiert und aufruft. Jetzt werden wir Pythons flexibles Parameter- und Argument-System im Detail erkunden. Wenn Sie diese Mechanismen verstehen, können Sie Funktionen schreiben, die sowohl leistungsfähig als auch einfach zu verwenden sind.

20.1) Positions- und Keyword-Argumente

Wenn Sie eine Funktion aufrufen, können Sie Argumente auf zwei grundlegende Arten übergeben: nach Position oder nach Name (Keyword).

20.1.1) Positionsargumente

Positionsargumente werden Parametern anhand ihrer Reihenfolge zugeordnet. Das erste Argument geht an den ersten Parameter, das zweite an den zweiten Parameter und so weiter.

python
def calculate_discount(price, discount_percent):
    """Calculate the final price after applying a discount."""
    discount_amount = price * (discount_percent / 100)
    final_price = price - discount_amount
    return final_price
 
# Übergabe von Argumenten nach Position
result = calculate_discount(100, 20)
print(result)

Output:

80.0

In diesem Beispiel wird 100 aufgrund seiner Position im Funktionsaufruf dem Parameter price zugewiesen und 20 dem Parameter discount_percent.

Die Reihenfolge ist bei Positionsargumenten entscheidend:

python
# Beispiel: Wir möchten einen Artikel für 100 $ mit 20 % Rabatt berechnen
 
# Richtige Reihenfolge: zuerst price, dann discount
print(calculate_discount(100, 20))
 
# Falsche Reihenfolge: zuerst discount, dann price
print(calculate_discount(20, 100))

Output:

80.0
-16.0

Wenn Sie die Argumente vertauschen, weiß Python nicht, dass Sie einen Fehler gemacht haben—es weist sie einfach der Reihenfolge nach zu. Das erzeugt ein mathematisch gültiges, aber logisch falsches Ergebnis (ein negativer Preis!).

20.1.2) Keyword-Argumente

Keyword-Argumente geben explizit an, welcher Parameter welchen Wert erhält, indem der Parametername gefolgt von einem Gleichheitszeichen und dem Wert verwendet wird. Das macht Ihren Code besser lesbar und schützt vor Reihenfolgefehlern.

python
def create_user_profile(username, email, age):
    """Create a user profile with the given information."""
    profile = f"User: {username}\nEmail: {email}\nAge: {age}"
    return profile
 
# Verwendung von Keyword-Argumenten
profile = create_user_profile(username="alice_smith", email="alice@example.com", age=28)
print(profile)

Output:

User: alice_smith
Email: alice@example.com
Age: 28

Bei Keyword-Argumenten spielt die Reihenfolge keine Rolle:

python
# Gleiches Ergebnis, andere Reihenfolge
profile1 = create_user_profile(username="bob", email="bob@example.com", age=35)
profile2 = create_user_profile(age=35, username="bob", email="bob@example.com")
profile3 = create_user_profile(email="bob@example.com", age=35, username="bob")
 
# Alle drei erzeugen identische Ergebnisse
print(profile1 == profile2 == profile3)

Output:

True

Diese Flexibilität ist besonders wertvoll, wenn eine Funktion viele Parameter hat, weil es leicht zu erkennen ist, welcher Wert welchem Parameter entspricht.

20.1.3) Positions- und Keyword-Argumente mischen

Sie können beide Stile in einem einzigen Funktionsaufruf kombinieren, aber es gibt eine wichtige Regel: Positionsargumente müssen vor Keyword-Argumenten stehen.

python
def format_address(street, city, state, zip_code):
    """Format a mailing address."""
    return f"{street}\n{city}, {state} {zip_code}"
 
# Gültig: zuerst Positionsargumente, dann Keyword-Argumente
address = format_address("123 Main St", "Springfield", state="IL", zip_code="62701")
print(address)

Output:

123 Main St
Springfield, IL 62701

Hier sind "123 Main St" und "Springfield" Positionsargumente (zugewiesen an street und city), während state und zip_code per Name angegeben werden.

Der Versuch, Positionsargumente nach Keyword-Argumenten zu platzieren, verursacht einen Fehler:

python
# Ungültig: Positionsargument nach Keyword-Argument
# address = format_address(street="123 Main St", "Springfield", state="IL", zip_code="62701")
# SyntaxError: positional argument follows keyword argument

Python erzwingt diese Regel, weil es, sobald Sie mit Keyword-Argumenten beginnen, unklar wird, welchen Positionsparameter ein nachfolgendes namenloses Argument füllen soll.

20.1.4) Wann welcher Stil sinnvoll ist

Verwenden Sie Positionsargumente, wenn:

  • Die Funktion wenige Parameter hat (typischerweise 1-3)
  • Die Parameterreihenfolge offensichtlich und intuitiv ist
  • Die Funktion häufig verwendet wird und die Reihenfolge gut bekannt ist
python
# Offensichtlich und knapp
print(len("hello"))
result = max(10, 20, 5)

Verwenden Sie Keyword-Argumente, wenn:

  • Die Funktion viele Parameter hat
  • Parametermedeutungen nicht sofort offensichtlich sind
  • Sie einige Parameter überspringen möchten, die Standardwerte haben (als Nächstes behandelt)
  • Sie Ihren Code selbstdokumentierend machen möchten
python
# Klar und explizit
user = create_user_profile(username="charlie", email="charlie@example.com", age=42)

20.2) Standardwerte für Parameter

Funktionen können für Parameter Standardwerte(default values) festlegen. Wenn ein Aufrufer für einen Parameter mit Standardwert kein Argument übergibt, verwendet Python stattdessen den Standardwert.

20.2.1) Parameter mit Standardwerten definieren

Standardwerte werden in der Funktionsdefinition mit dem Zuweisungsoperator angegeben:

python
def greet_user(name, greeting="Hello"):
    """Greet a user with a customizable greeting."""
    return f"{greeting}, {name}!"
 
# Verwendung der Standardbegrüßung
print(greet_user("Alice"))
 
# Bereitstellen einer benutzerdefinierten Begrüßung
print(greet_user("Bob", "Good morning"))
print(greet_user("Carol", greeting="Hi"))

Output:

Hello, Alice!
Good morning, Bob!
Hi, Carol!

Der Parameter greeting hat den Standardwert "Hello". Wenn Sie greet_user("Alice") aufrufen, verwendet Python diesen Standardwert. Wenn Sie ein zweites Argument angeben, überschreibt es den Standard.

20.2.2) Parameter mit Standardwerten müssen nach Pflichtparametern stehen

Python verlangt, dass Parameter mit Standardwerten nach allen Parametern ohne Standardwerte stehen. Diese Regel verhindert Unklarheiten darüber, welche Argumente welchen Parametern entsprechen.

python
# Richtig: zuerst Pflichtparameter, dann Standardwerte
def create_product(name, price, category="General", in_stock=True):
    """Create a product record."""
    return {
        "name": name,
        "price": price,
        "category": category,
        "in_stock": in_stock
    }
 
product = create_product("Laptop", 999.99)
print(product)

Output:

{'name': 'Laptop', 'price': 999.99, 'category': 'General', 'in_stock': True}

Der Versuch, einen Pflichtparameter nach einem Parameter mit Standardwert zu platzieren, führt zu einem Syntaxfehler:

python
# Ungültig: Pflichtparameter nach Default-Parameter
# def invalid_function(name="Unknown", age):
#     return f"{name} is {age} years old"
# SyntaxError: non-default argument follows default argument

Das ist nachvollziehbar: Wenn name einen Standard hat, age aber nicht, woher sollte Python wissen, ob invalid_function(25) name=25 mit fehlendem age bedeutet, oder age=25 mit name auf Standardwert? Die Regel beseitigt diese Mehrdeutigkeit.

20.2.3) Praktische Anwendungen von Standardparametern

Standardparameter sind hervorragend für Funktionen, bei denen sich bestimmte Argumente selten ändern:

python
def calculate_shipping(weight, distance, express=False):
    """Calculate shipping cost based on weight and distance."""
    base_rate = 0.50 * weight + 0.10 * distance
    
    if express:
        base_rate *= 2  # Expressversand kostet das Doppelte
    
    return round(base_rate, 2)
 
# Die meisten Sendungen sind Standard
standard_cost = calculate_shipping(5, 100)
print(f"Standard: ${standard_cost}")
 
# Manchmal braucht jemand Express
express_cost = calculate_shipping(5, 100, express=True)
print(f"Express: ${express_cost}")

Output:

Standard: $12.5
Express: $25.0

Dieses Design macht den häufigen Fall (Standardversand) einfach aufzurufen, unterstützt aber weiterhin den weniger häufigen Fall (Expressversand), wenn er benötigt wird.

20.2.4) Mehrere Standardwerte und selektives Überschreiben

Wenn eine Funktion mehrere Parameter mit Standardwerten hat, können Sie jede beliebige Kombination davon mit Keyword-Argumenten überschreiben:

python
def format_currency(amount, currency="USD", show_symbol=True, decimal_places=2):
    """Format a number as currency."""
    symbols = {"USD": "$", "EUR": "€", "GBP": "£", "JPY": "¥"}
    
    formatted = f"{amount:.{decimal_places}f}"
    
    if show_symbol and currency in symbols:
        formatted = f"{symbols[currency]}{formatted}"
    
    return formatted
 
# Alle Standardwerte verwenden
print(format_currency(42.5))
 
# Nur die currency überschreiben
print(format_currency(42.5, currency="EUR"))
 
# Mehrere Standardwerte überschreiben
print(format_currency(42.5, currency="JPY", decimal_places=0))

Output:

$42.50
€42.50
¥42

Diese Flexibilität ermöglicht es Aufrufern, genau das zu konfigurieren, was sie brauchen, während der Funktionsaufruf knapp bleibt.

20.3) Argumentlisten variabler Länge mit *args

Manchmal möchten Sie, dass eine Funktion eine beliebige Anzahl von Argumenten akzeptiert, ohne im Voraus zu wissen, wie viele es sein werden. Python stellt dafür *args bereit.

20.3.1) *args verstehen

Die Syntax *args in einer Parameterliste sammelt alle zusätzlichen Positionsargumente in einem Tupel. Der Name args ist eine Konvention (Kurzform für „arguments“), aber Sie können nach dem Sternchen jeden gültigen Parameternamen verwenden.

python
def calculate_total(*numbers):
    """Calculate the sum of any number of values."""
    total = 0
    for num in numbers:
        total += num
    return total
 
# Funktioniert mit jeder Anzahl von Argumenten
print(calculate_total(10))
print(calculate_total(10, 20))
print(calculate_total(10, 20, 30, 40))
print(calculate_total())

Output:

10
30
100
0

Innerhalb der Funktion ist numbers ein Tupel, das alle Positionsargumente enthält, die an die Funktion übergeben wurden. Wenn keine Argumente angegeben werden, ist es ein leeres Tupel.

20.3.2) Reguläre Parameter mit *args kombinieren

Sie können reguläre Parameter vor *args haben. Die regulären Parameter verbrauchen die ersten paar Argumente, und *args sammelt den Rest:

python
def create_team(team_name, *members):
    """Create a team with a name and any number of members."""
    member_list = ", ".join(members)
    return f"Team {team_name}: {member_list}"
 
# Das erste Argument geht an team_name, der Rest an members
print(create_team("Alpha", "Alice", "Bob"))
print(create_team("Beta", "Carol"))
print(create_team("Gamma", "Dave", "Eve", "Frank", "Grace"))

Output:

Team Alpha: Alice, Bob
Team Beta: Carol
Team Gamma: Dave, Eve, Frank, Grace

Das erste Argument ("Alpha", "Beta" oder "Gamma") wird team_name zugewiesen, und alle verbleibenden Argumente werden im Tupel members gesammelt.

20.4) Keyword-only- und **kwargs-Parameter

Python bietet zwei zusätzliche Mechanismen für den Umgang mit Argumenten: Keyword-only-Parameter und **kwargs zum Sammeln beliebiger Keyword-Argumente.

20.4.1) Keyword-only-Parameter

Keyword-only-Parameter müssen als Keyword-Argumente angegeben werden—sie können nicht positionsbasiert übergeben werden. Sie erstellen sie, indem Sie sie nach einem * oder nach *args in der Parameterliste platzieren.

python
def create_account(username, *, email, age):
    """Create an account. Email and age must be specified by name."""
    return {
        "username": username,
        "email": email,
        "age": age
    }
 
# Richtig: email und age als Keyword angegeben
account = create_account("alice", email="alice@example.com", age=28)
print(account)
 
# Ungültig: Versuch, email und age positionsbasiert zu übergeben
# account = create_account("bob", "bob@example.com", 30)
# TypeError: create_account() takes 1 positional argument but 3 were given

Output:

{'username': 'alice', 'email': 'alice@example.com', 'age': 28}

Das * in der Parameterliste fungiert als Trenner. Alles danach muss als Keyword-Argument übergeben werden. Das ist nützlich, wenn Sie möchten, dass Aufrufer bei bestimmten Parametern explizit sind, wodurch der Code lesbarer und weniger fehleranfällig wird.

Sie können auch reguläre Parameter, *args und Keyword-only-Parameter kombinieren:

python
def log_event(event_type, *details, severity="INFO", timestamp=None):
    """Log an event with optional details and metadata."""
    # Wir werden das datetime-Modul in Kapitel 39 im Detail kennenlernen,
    # aber fürs Erste reicht es zu wissen, dass diese Zeilen die aktuelle Zeit holen
    # und sie als Zeitstempel-String formatieren
    from datetime import datetime
    
    if timestamp is None:
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    details_str = " | ".join(details)
    return f"[{timestamp}] {severity}: {event_type} - {details_str}"
 
# event_type ist positional, details werden von *details gesammelt,
# severity und timestamp sind keyword-only
print(log_event("Login", "User: alice", "IP: 192.168.1.1"))
print(log_event("Error", "Database connection failed", severity="ERROR"))

Output (timestamp will vary based on when you run the code):

[2025-12-18 19:29:16] INFO: Login - User: alice | IP: 192.168.1.1
[2025-12-18 19:29:16] ERROR: Error - Database connection failed

20.4.2) **kwargs verstehen

Die Syntax **kwargs sammelt alle zusätzlichen Keyword-Argumente in einem Dictionary (dict). Wie bei args ist der Name kwargs konventionell (Kurzform für „keyword arguments“), aber Sie können nach den zwei Sternchen jeden gültigen Namen verwenden.

python
def create_product(**attributes):
    """Create a product with any number of attributes."""
    product = {}
    for key, value in attributes.items():
        product[key] = value
    return product
 
# Übergeben Sie beliebige Keyword-Argumente
laptop = create_product(name="Laptop", price=999.99, brand="TechCorp", in_stock=True)
print(laptop)
 
phone = create_product(name="Phone", price=699.99, color="Black")
print(phone)

Output:

{'name': 'Laptop', 'price': 999.99, 'brand': 'TechCorp', 'in_stock': True}
{'name': 'Phone', 'price': 699.99, 'color': 'Black'}

Innerhalb der Funktion ist attributes ein Dictionary, bei dem die Schlüssel die Parameternamen und die Werte die übergebenen Argumente sind.

20.4.3) Reguläre Parameter, *args und **kwargs kombinieren

Sie können all diese Mechanismen zusammen verwenden, aber sie müssen in einer bestimmten Reihenfolge erscheinen:

  1. Reguläre Positionsparameter
  2. *args (falls vorhanden)
  3. Keyword-only-Parameter (falls vorhanden)
  4. **kwargs (falls vorhanden)
python
def complex_function(required, *args, keyword_only, **kwargs):
    """Demonstrate all parameter types together."""
    print(f"Required: {required}")
    print(f"Args: {args}")
    print(f"Keyword-only: {keyword_only}")
    print(f"Kwargs: {kwargs}")
 
complex_function(
    "value1",           # required
    "value2", "value3", # args
    keyword_only="kw",  # keyword_only
    extra1="e1",        # kwargs
    extra2="e2"         # kwargs
)

Output:

Required: value1
Args: ('value2', 'value3')
Keyword-only: kw
Kwargs: {'extra1': 'e1', 'extra2': 'e2'}

Diese Flexibilität ist leistungsfähig, sollte aber mit Bedacht verwendet werden. Die meisten Funktionen benötigen nicht all diese Mechanismen.

20.4.4) Praktischer Anwendungsfall: Konfigurationsfunktionen

Ein häufiger Einsatz für **kwargs ist das Erstellen von Funktionen, die Konfigurationsoptionen akzeptieren:

python
def connect_to_database(host, port, **options):
    """Connect to a database with flexible configuration options."""
    connection_string = f"Connecting to {host}:{port}"
    
    # Zusätzliche Optionen verarbeiten
    if options.get("ssl"):
        connection_string += " with SSL"
    
    if options.get("timeout"):
        connection_string += f" (timeout: {options['timeout']}s)"
    
    if options.get("pool_size"):
        connection_string += f" (pool size: {options['pool_size']})"
    
    return connection_string
 
# Basisverbindung
print(connect_to_database("localhost", 5432))
 
# Mit SSL
print(connect_to_database("db.example.com", 5432, ssl=True))
 
# Mit mehreren Optionen
print(connect_to_database("db.example.com", 5432, ssl=True, timeout=30, pool_size=10))

Output:

Connecting to localhost:5432
Connecting to db.example.com:5432 with SSL
Connecting to db.example.com:5432 with SSL (timeout: 30s) (pool size: 10)

Dieses Muster ermöglicht es der Funktion, beliebig viele optionale Konfigurationsparameter zu akzeptieren, ohne sie alle explizit in der Parameterliste zu definieren.

Positionsbasiert

Zusätzliche Positionsargumente

Nur-Keyword

Zusätzliche Keyword-Argumente

Funktionsaufruf

Parametertyp?

Reguläre Parameter

*args-Tupel

Keyword-only-Parameter

**kwargs-Dictionary

Nach Position zugewiesen

In Tupel gesammelt

Muss per Name angegeben werden

In Dictionary gesammelt

20.5) Argument-Unpacking beim Aufruf von Funktionen

So wie *args und **kwargs Argumente beim Definieren von Funktionen sammeln, können Sie * und ** verwenden, um Sammlungen beim Aufruf von Funktionen zu entpacken.

20.5.1) Sequenzen mit * entpacken

Der Operator * entpackt eine Sequenz (Liste (list), Tupel usw.) in separate Positionsargumente:

python
def calculate_rectangle_area(width, height):
    """Calculate the area of a rectangle."""
    return width * height
 
# Statt Argumente einzeln zu übergeben
dimensions = [5, 10]
area = calculate_rectangle_area(dimensions[0], dimensions[1])
print(area)
 
# Die Liste direkt entpacken
area = calculate_rectangle_area(*dimensions)
print(area)

Output:

50
50

Wenn Sie *dimensions schreiben, entpackt Python die Liste [5, 10] in zwei separate Argumente, als hätten Sie calculate_rectangle_area(5, 10) geschrieben.

Das funktioniert mit jedem Iterable:

python
def format_name(first, middle, last):
    """Format a full name."""
    return f"{first} {middle} {last}"
 
# Ein Tupel entpacken
name_tuple = ("John", "Q", "Public")
print(format_name(*name_tuple))
 
# Eine Liste entpacken
name_list = ["Jane", "M", "Doe"]
print(format_name(*name_list))
 
# Sogar einen String entpacken (jedes Zeichen wird zu einem Argument)
# Das funktioniert nur, wenn die Funktion die richtige Anzahl an Argumenten erwartet
def show_first_three(a, b, c):
    return f"{a}, {b}, {c}"
 
print(show_first_three(*"ABC"))

Output:

John Q Public
Jane M Doe
A, B, C

20.5.2) Dictionaries mit ** entpacken

Der Operator ** entpackt ein Dictionary in Keyword-Argumente:

python
def create_user(username, email, age):
    """Create a user profile."""
    return f"User: {username}, Email: {email}, Age: {age}"
 
# Dictionary mit Schlüsseln, die den Parameternamen entsprechen
user_data = {
    "username": "alice",
    "email": "alice@example.com",
    "age": 28
}
 
# Das Dictionary entpacken
profile = create_user(**user_data)
print(profile)

Output:

User: alice, Email: alice@example.com, Age: 28

Wenn Sie **user_data schreiben, entpackt Python das Dictionary in Keyword-Argumente, äquivalent zu:

python
create_user(username="alice", email="alice@example.com", age=28)

Die Dictionary-Schlüssel müssen zu den Parameternamen der Funktion passen, sonst erhalten Sie einen Fehler:

python
# Ungültig: Dictionary-Schlüssel passt nicht zum Parameternamen
invalid_data = {"name": "bob", "email": "bob@example.com", "age": 30}
# profile = create_user(**invalid_data)
# TypeError: create_user() got an unexpected keyword argument 'name'

20.5.3) Unpacking mit regulären Argumenten kombinieren

Sie können entpackte Argumente mit regulären Argumenten mischen:

python
def calculate_total(base_price, tax_rate, discount):
    """Calculate total price after tax and discount."""
    subtotal = base_price * (1 + tax_rate)
    total = subtotal * (1 - discount)
    return round(total, 2)
 
# Einige Argumente regulär, einige entpackt
pricing = [0.08, 0.10]  # tax_rate and discount
total = calculate_total(100, *pricing)
print(total)

Output:

97.2

Sie können auch mehrere Collections in einem einzigen Aufruf entpacken:

python
def create_full_address(street, city, state, zip_code, country):
    """Create a complete address."""
    return f"{street}, {city}, {state} {zip_code}, {country}"
 
street_address = ["123 Main St", "Springfield"]
location_details = ["IL", "62701", "USA"]
 
address = create_full_address(*street_address, *location_details)
print(address)

Output:

123 Main St, Springfield, IL 62701, USA

20.5.4) Praktisches Beispiel: Flexible Funktionsaufrufe

Unpacking ist besonders nützlich, wenn Sie mit Daten aus externen Quellen arbeiten:

python
def send_email(recipient, subject, body, cc=None, bcc=None):
    """Send an email with optional CC and BCC."""
    message = f"To: {recipient}\nSubject: {subject}\n\n{body}"
    
    if cc:
        message += f"\nCC: {cc}"
    if bcc:
        message += f"\nBCC: {bcc}"
    
    return message
 
# E-Mail-Daten aus einer Konfigurationsdatei oder Datenbank
email_config = {
    "recipient": "user@example.com",
    "subject": "Welcome",
    "body": "Thank you for signing up!",
    "cc": "manager@example.com"
}
 
# Die Konfiguration direkt entpacken
result = send_email(**email_config)
print(result)

Output:

To: user@example.com
Subject: Welcome
 
Thank you for signing up!
CC: manager@example.com

Dieses Muster macht es leicht, Funktionsargumente als Datenstrukturen herumzureichen, was beim Erstellen von APIs oder beim Verarbeiten von Konfigurationsdateien üblich ist.

* operator

** operator

Collection

Unpacking-Typ

Sequenz-Unpacking

Dictionary-Unpacking

List/Tuple → Positionsargumente

Dict → Keyword-Argumente

Funktionsaufruf

20.6) Die Falle veränderlicher Standardargumente (Warum Listen-Defaults bestehen bleiben)

Eine der berüchtigtsten Fallstricke in Python betrifft die Verwendung veränderlicher Objekte (wie Listen oder Dictionaries) als Standardwerte für Parameter. Dieses Problem zu verstehen ist entscheidend, um korrekte Funktionen zu schreiben.

20.6.1) Das Problem: Geteilte veränderliche Defaults

Betrachten Sie diese scheinbar harmlose Funktion:

python
def add_student(name, grades=[]):
    """Add a student with their grades."""
    grades.append(name)
    return grades
 
# Erster Aufruf
students1 = add_student("Alice")
print(students1)
 
# Zweiter Aufruf - erwartet eine frische Liste
students2 = add_student("Bob")
print(students2)
 
# Dritter Aufruf
students3 = add_student("Carol")
print(students3)

Output:

['Alice']
['Alice', 'Bob']
['Alice', 'Bob', 'Carol']

Dieses Verhalten überrascht viele Programmierer. Jeder Aufruf von add_student() ohne ein grades-Argument verwendet dasselbe Listenobjekt, nicht ein neues. Die Liste bleibt über Funktionsaufrufe hinweg bestehen und sammelt Werte an.

20.6.2) Warum das passiert: Standardwerte werden einmal erstellt

Der Schlüssel zum Verständnis dieses Verhaltens ist zu wissen, wann Standardwerte erstellt werden. Python wertet Standardwerte für Parameter einmal aus, wenn die Funktion definiert wird, nicht jedes Mal, wenn die Funktion aufgerufen wird.

python
def demonstrate_default_creation():
    """Show when defaults are created."""
    print("Function defined!")
 
def use_default(value=demonstrate_default_creation()):
    """Use a default that calls a function."""
    return value
 
# Die Nachricht wird ausgegeben, wenn die Funktion DEFINIERT wird, nicht aufgerufen

Output:

Function defined!

Wenn Python auf die Zeile def use_default trifft, wertet es den Standardparameter value=demonstrate_default_creation() aus. Das ruft demonstrate_default_creation() auf, was sofort „Function defined!“ ausgibt. Spätere Aufrufe von use_default() werten den Standard nicht erneut aus, daher wird nichts zusätzlich ausgegeben.

Wenn Python auf def add_student(name, grades=[]): trifft, erstellt es ein leeres Listenobjekt und speichert es als Standardwert für grades. Jeder nachfolgende Aufruf, der kein grades-Argument bereitstellt, verwendet genau dieses Listenobjekt.

Hier ist eine deutlichere Demonstration mit Objektidentität:

python
def show_list_identity(items=[]):
    """Show that the same list object is reused."""
    print(f"List ID: {id(items)}")
    items.append("item")
    return items
 
# Jeder Aufruf verwendet dasselbe Listenobjekt (gleiche ID)
show_list_identity()
show_list_identity()
show_list_identity()

Output:

List ID: 140234567890123
List ID: 140234567890123
List ID: 140234567890123

Die genauen ID-Nummern unterscheiden sich auf Ihrem System, aber beachten Sie, dass alle drei Aufrufe denselben ID-Wert zeigen, was beweist, dass sie dasselbe Listenobjekt verwenden. Die Funktion id() gibt einen eindeutigen Identifikator für jedes Objekt im Speicher zurück—wenn die IDs übereinstimmen, ist es dasselbe Objekt.

20.6.3) Das korrekte Muster: None als Standard verwenden

Die Standardlösung besteht darin, None als Standard zu verwenden und innerhalb der Funktion ein neues veränderliches Objekt zu erstellen:

python
def add_student_correct(name, grades=None):
    """Add a student with their grades (correct version)."""
    if grades is None:
        grades = []  # Jedes Mal eine NEUE Liste erstellen
    
    grades.append(name)
    return grades
 
# Jetzt bekommt jeder Aufruf seine eigene Liste
students1 = add_student_correct("Alice")
print(students1)
 
students2 = add_student_correct("Bob")
print(students2)
 
students3 = add_student_correct("Carol")
print(students3)

Output:

['Alice']
['Bob']
['Carol']

Dieses Muster funktioniert, weil None unveränderlich ist und jedes Mal im Funktionskörper eine neue Liste erstellt wird, wenn grades None ist.

20.6.4) Dasselbe Problem mit Dictionaries

Dieses Problem betrifft alle veränderlichen Typen, nicht nur Listen:

python
# FALSCH: Dictionary als Standard
def create_config_wrong(key, value, config={}):
    """Create a configuration (BUGGY VERSION)."""
    config[key] = value
    return config
 
config1 = create_config_wrong("theme", "dark")
print(config1)
 
config2 = create_config_wrong("language", "en")
print(config2)
 
print("---")
 
# RICHTIG: None als Standard
def create_config_correct(key, value, config=None):
    """Create a configuration (CORRECT VERSION)."""
    if config is None:
        config = {}
    
    config[key] = value
    return config
 
config1 = create_config_correct("theme", "dark")
print(config1)
 
config2 = create_config_correct("language", "en")
print(config2)

Output:

{'theme': 'dark'}
{'theme': 'dark', 'language': 'en'}
---
{'theme': 'dark'}
{'language': 'en'}

20.6.5) Zusammenfassung: Die goldene Regel

Verwenden Sie niemals veränderliche Objekte (Listen, Dictionaries, Sets) als Standardwerte für Parameter. Verwenden Sie immer None und erstellen Sie das veränderliche Objekt innerhalb der Funktion:

python
# ❌ WRONG
def function(items=[]):
    pass
 
# ✅ CORRECT
def function(items=None):
    if items is None:
        items = []
    # items jetzt sicher verwenden

Dieses Muster stellt sicher, dass jeder Funktionsaufruf sein eigenes, unabhängiges veränderliches Objekt erhält, und verhindert mysteriöse Bugs, bei denen Daten zwischen Aufrufen „auslaufen“.


In diesem Kapitel haben wir Pythons flexibles Parameter- und Argument-System im Detail untersucht. Sie haben gelernt, wie Sie Positions- und Keyword-Argumente verwenden, Standardwerte bereitstellen, eine variable Anzahl von Argumenten mit *args und **kwargs verarbeiten, Sammlungen beim Aufruf von Funktionen entpacken und die Falle veränderlicher Standardargumente vermeiden.

Diese Mechanismen geben Ihnen leistungsfähige Werkzeuge an die Hand, um Funktionsschnittstellen zu entwerfen, die sowohl flexibel als auch einfach zu verwenden sind. Während Sie mehr Funktionen schreiben, entwickeln Sie ein Gespür dafür, welche Parametermuster am besten zu unterschiedlichen Situationen passen. Der Schlüssel ist, Flexibilität mit Klarheit zu balancieren—machen Sie Ihre Funktionen leicht korrekt aufzurufen und schwer falsch aufzurufen.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai