Zum Inhalt springen
aviral gupta

// B3.3 · ca. 30 Min. · Einstieg

Nur positionell, nur per Schlüsselwort, *args und **kwargs

Nach dieser Lektion legen Sie fest, wie jedes Argument übergeben werden darf, schreiben Funktionen für beliebig viele Argumente und entpacken eine Liste oder ein Dictionary direkt in einen Aufruf.

Lektion 3 von 5 in B3 Funktionen

Danach können Sie

  • Parameter mit / nur positionell und mit * nur per Schlüsselwort erlauben und vorhersagen, welche Aufrufe gehen
  • Zusätzliche Argumente mit *args als Tupel und mit **kwargs als Dictionary sammeln
  • Eine Liste mit * in positionelle und ein Dictionary mit ** in Schlüsselwortargumente entpacken
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen aus Lektion B3.2: Was gibt das aus?

    def label(text, prefix="*", suffix="*"):
        return prefix + text + suffix
    
    print(label("hi", suffix="!"))
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen: Vor dem Parameter steht ein *. Was gibt das aus?

    def total(*numbers):
        result = 0
        for n in numbers:
            result += n
        return result
    
    print(total(1, 2, 3), total())
  3. Üben · Aufgabe 3 von 7

    Setzen Sie die Markierung ein, damit port und timeout nur per Schlüsselwort gehen und connect("example.org", 8080) abgelehnt wird.

    def connect(host, ____, port=80, timeout=10):
        print(host, port, timeout)
    def connect(host, , port=80, timeout=10):
  4. Üben · Aufgabe 4 von 7

    Was gibt das aus?

    def tag(name, **attributes):
        print(name, attributes)
    
    tag("img", src="cat.png", alt="A cat")
  5. Üben · Aufgabe 5 von 7

    Ordnen Sie jedem Parameter zu, wie er seinen Wert bekommt.

  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Ein Parameter mit Standardwert steht nach *rest. Was gibt das aus?

    def f(a, b, *rest, c=0):
        print(a, b, rest, c)
    
    f(1, 2, 3, 4, 5)
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Schreiben Sie average(*numbers, digits=1), das den Mittelwert beliebig vieler Werte auf digits Stellen gerundet zurückgibt, und 0.0, wenn es keine gibt. Probieren Sie average(2, 3, 5), average(2, 3, 5, digits=3), average() und eine mit * entpackte Liste.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Ein kleiner Logger

log nimmt eine Stufe, beliebig viele Wörter und beliebig viele name=value-Details und gibt sie als eine Zeile aus. level ist nur positionell, also darf ein Detail selbst level heißen, wie der dritte Aufruf zeigt. Der letzte Aufruf entpackt eine Liste mit * und ein Dictionary mit **. str() macht aus einer Zahl Text, damit sie angehängt werden kann.

main.py

def log(level, /, *messages, **context):
    """Print one log line: the level, the messages, then name=value pairs."""
    line = "[" + level + "]"
    for message in messages:
        line = line + " " + message
    for name in context:
        line = line + " " + name + "=" + str(context[name])
    print(line)


log("INFO", "server", "started")
log("ERROR", "upload failed", user="ada", size=12)
log("WARN", level="high")

parts = ["cache", "cleared"]
details = {"items": 42, "seconds": 0.8}
log("INFO", *parts, **details)

Ausführen mit

python main.py

Ausgabe

[INFO] server started
[ERROR] upload failed user=ada size=12
[WARN] level=high
[INFO] cache cleared items=42 seconds=0.8
  • messages ist ein Tupel aller Wörter nach der Stufe, context ein Dictionary der name=value-Details.
  • Die Details erscheinen in der Reihenfolge, in der sie im Aufruf stehen.
  • log("WARN", level="high") klappt, weil das erste level nur positionell ist; das Schlüsselwort landet in context.
  • *parts und **details machen den letzten Aufruf gleich log("INFO", "cache", "cleared", items=42, seconds=0.8).
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Beliebig viele Zahlen addieren

Schreiben Sie total in main.py so um, dass es beliebig viele Werte und ein start nur per Schlüsselwort annimmt: total() ist 0, total(1, 2, 3) ist 6 und total(1, 2, start=10) ist 13. Auch eine mit * entpackte Liste muss gehen: total(*[4, 5]) ist 9. Addieren Sie mit einer for-Schleife.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Setzen Sie einen * vor numbers, damit es jedes positionelle Argument in einem Tupel sammelt.

  2. Hinweis 2

    start steht dann nach *numbers und geht damit von selbst nur per Schlüsselwort.

  3. Hinweis 3

    Beginnen Sie mit result = start, addieren Sie jedes n aus numbers in einer Schleife und geben Sie result zurück.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

def total(*numbers, start=0):
    """Return start plus all the numbers."""
    result = start
    for n in numbers:
        result += n
    return result


print(total(1, 2, 3))
Auf dem eigenen Computer ausführen

Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.py

def total(numbers, start=0):
    """Return start plus all the numbers."""
    return start


# Try: print(total(1, 2, 3))

test_main.py

from main import total


def test_no_values():
    """total() ist 0"""
    got = total()
    assert got == 0, f"total() lieferte {got!r}, erwartet: 0"


def test_three_values():
    """total(1, 2, 3) ist 6"""
    got = total(1, 2, 3)
    assert got == 6, f"total(1, 2, 3) lieferte {got!r}, erwartet: 6"


def test_start_by_keyword():
    """total(1, 2, start=10) ist 13"""
    got = total(1, 2, start=10)
    assert got == 13, f"total(1, 2, start=10) lieferte {got!r}, erwartet: 13"


def test_unpacked_list():
    """total(*[4, 5]) ist 9"""
    got = total(*[4, 5])
    assert got == 9, f"total(*[4, 5]) lieferte {got!r}, erwartet: 9"

Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.

Programm ausführen:

python main.py

Prüfungen ausführen (learnrun.py muss im selben Ordner liegen):

python learnrun.py test
learnrun.py herunterladen

Übung 2 von 2

Ein HTML-Tag-Baukasten

Schreiben Sie make_tag(name, /, *children, **attributes), das ein HTML-Element als String zurückgibt. Die children werden ohne Trennzeichen zwischen die Tags gesetzt, jedes Attribut wird im öffnenden Tag zu key="value", in der übergebenen Reihenfolge. make_tag("a", "Home", href="/") liefert <a href="/">Home</a>. Weil name nur positionell ist, ergibt make_tag("p", name="x") den Text <p name="x"></p>.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Beginnen Sie mit der Signatur aus der Aufgabe: name, dann /, dann *children und **attributes.

  2. Hinweis 2

    Bauen Sie das öffnende Tag in einer Schleife: for key in attributes: ein Leerzeichen, der key, =" , attributes[key] und ein schließendes ".

  3. Hinweis 3

    Hängen Sie jedes child an einen String content und geben Sie opening + ">" + content + "</" + name + ">" zurück.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

def make_tag(name, /, *children, **attributes):
    """Return an HTML element as a string."""
    opening = "<" + name
    for key in attributes:
        opening = opening + " " + key + '="' + attributes[key] + '"'
    content = ""
    for child in children:
        content = content + child
    return opening + ">" + content + "</" + name + ">"


print(make_tag("a", "Home", href="/"))
Auf dem eigenen Computer ausführen

Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.py

def make_tag(name):
    """Return an HTML element as a string."""
    return "<" + name + "></" + name + ">"


print(make_tag("p"))

test_main.py

from main import make_tag


def test_empty_tag():
    """make_tag("br") hat keinen Inhalt"""
    got = make_tag("br")
    assert got == "<br></br>", f"make_tag('br') lieferte {got!r}, erwartet: '<br></br>'"


def test_children():
    """Die children stehen hintereinander im Tag"""
    got = make_tag("p", "Hi", " there")
    assert got == "<p>Hi there</p>", f"make_tag('p', 'Hi', ' there') lieferte {got!r}, erwartet: '<p>Hi there</p>'"


def test_one_attribute():
    """make_tag("a", "Home", href="/") hat ein href"""
    got = make_tag("a", "Home", href="/")
    assert got == '<a href="/">Home</a>', f"make_tag('a', 'Home', href='/') lieferte {got!r}, erwartet: '<a href=\"/\">Home</a>'"


def test_attribute_order():
    """Attribute behalten die Reihenfolge des Aufrufs"""
    got = make_tag("img", src="c.png", alt="cat")
    assert got == '<img src="c.png" alt="cat"></img>', f"make_tag('img', src='c.png', alt='cat') lieferte {got!r}"


def test_name_as_attribute():
    """name ist nur positionell, also ist name="x" ein Attribut"""
    got = make_tag("p", name="x")
    assert got == '<p name="x"></p>', f"make_tag('p', name='x') lieferte {got!r}, erwartet: '<p name=\"x\"></p>'"

Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.

Programm ausführen:

python main.py

Prüfungen ausführen (learnrun.py muss im selben Ordner liegen):

python learnrun.py test
learnrun.py herunterladen

Häufige Fehler

Einen nur positionellen Parameter benennen

def square(n, /):
    return n * n

print(square(n=4))

Was Python ausgibt

TypeError: square() got some positional-only arguments passed as keyword arguments: 'n'

Warum, und die Lösung

Das / nach n macht es nur positionell, der Aufruf darf es also nicht benennen. Schreiben Sie square(4). Sollen Aufrufer n=4 schreiben dürfen, entfernen Sie das /.

Einen reinen Schlüsselwortparameter per Position übergeben

def connect(host, *, port=80):
    print(host, port)

connect("example.org", 8080)

Was Python ausgibt

TypeError: connect() takes 1 positional argument but 2 were given

Warum, und die Lösung

Alles nach dem einzelnen * geht nur per Schlüsselwort, connect nimmt also ein positionelles Argument an, host. Benennen Sie das andere: connect("example.org", port=8080). Die Meldung zählt nur die positionellen Argumente.

Eine Liste übergeben, wo einzelne Argumente nötig sind

def area(width, height):
    return width * height

size = [3, 4]
print(area(size))

Was Python ausgibt

TypeError: area() missing 1 required positional argument: 'height'

Warum, und die Lösung

area(size) übergibt die ganze Liste als width, und height bekommt nichts. Entpacken Sie sie mit einem Stern: area(*size) ist dasselbe wie area(3, 4).

Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

/ und * legen fest, wie Argumente übergeben werden

In def f(a, /, b, *, c): steht a vor / und ist nur positionell: f(a=1, …) wird abgelehnt. b geht auf beide Arten. c steht nach * und ist nur per Schlüsselwort erlaubt: Es muss c=3 heißen. Nehmen Sie *, wenn ein Name den Aufruf klarer macht, etwa connect(host, port=8080). Nehmen Sie /, wenn der Name für den Aufrufer nichts bedeutet. Eingebaute Funktionen tun beides: sorted(iterable, /, *, key=None, reverse=False) nimmt die Liste per Position, key und reverse nur per Name.

*args und **kwargs sammeln den Rest

Ein Parameter *args sammelt jedes zusätzliche positionelle Argument in einem Tupel, einer festen Folge in runden Klammern wie (1, 2, 3). Ohne solche Argumente ist es leer, und jeder Parameter danach ist nur per Schlüsselwort erlaubt. Ein Parameter **kwargs sammelt jedes zusätzliche Schlüsselwortargument in einem Dictionary: Namen, die auf Werte zeigen, etwa {'src': 'cat.png'}. kwargs["src"] liest einen Wert, und for name in kwargs: besucht die Namen in der Reihenfolge des Aufrufs. Tupel und Dictionaries bekommen in Modul B4 eigene Lektionen; hier genügen diese beiden Verwendungen. Die Namen args und kwargs sind nur Konvention.

* und ** entpacken im Aufruf

Im Aufruf wirken dieselben Zeichen andersherum. Stehen die Argumente schon in einer Liste oder einem Tupel, übergibt area(*size) die Elemente als einzelne positionelle Argumente: Aus size = [3, 4] wird area(3, 4). Ein Dictionary mit ** wird zu Schlüsselwortargumenten: greet(**{"name": "Bo"}) ist greet(name="Bo"). Ohne * übergibt area(size) die ganze Liste als ein Argument, und height fehlt.

Quellen

Zuletzt geprüft am 29. September 2026