Ich war immer überrascht , dass mit den Argumenten von Python - Funktionen an der Arbeit, die Sie brauchen nur zu verstehen ,
*argsund **kwargs. Und ich war nicht umsonst überrascht. Wie sich herausstellt, sind Argumente alles andere als einfach. In diesem Beitrag möchte ich einen allgemeinen Überblick über alles geben, was mit Funktionsargumenten in Python zu tun hat. Ich hoffe, dass ich am Ende tatsächlich das allgemeine Bild der Arbeit mit Argumenten zeigen kann und dass dieser Artikel keine weitere Veröffentlichung wird, in der der Leser nichts Neues finden kann. Und jetzt - auf den Punkt.
Ich denke, die meisten Leser dieses Artikels verstehen die Essenz von Funktionsargumenten. Lassen Sie mich für Anfänger erklären, dass dies Objekte sind, die vom Initiator ihres Aufrufs an eine Funktion gesendet werden. Beim Übergeben von Argumenten an eine Funktion werden viele Aktionen ausgeführt, je nachdem, welcher Objekttyp an die Funktion gesendet wird (veränderbare oder unveränderliche Objekte). Ein Funktionsaufrufinitiator ist eine Entität, die eine Funktion aufruft und ihr Argumente übergibt. Apropos aufrufende Funktionen, es gibt einige Dinge zu beachten, die wir jetzt diskutieren werden.
Die Argumente, deren Namen beim Deklarieren der Funktion angegeben werden, speichern die Objekte, die beim Aufruf an die Funktion übergeben werden. Wenn den entsprechenden lokalen Variablen von Funktionen, ihren Parametern, etwas zugewiesen wird, wirkt sich diese Operation nicht auf die unveränderlichen Objekte aus, die an die Funktionen übergeben werden. Zum Beispiel:
def foo(a):
a = a+5
print(a) # 15
a = 10
foo(a)
print(a) # 10
Wie Sie sehen, hat der Funktionsaufruf die Variable in keiner Weise beeinflusst
a. Genau dies passiert, wenn ein unveränderliches Objekt an eine Funktion übergeben wird.
Wenn veränderbare Objekte an Funktionen übergeben werden, kann es zu einem Systemverhalten kommen, das sich von den oben genannten unterscheidet.
def foo(lst):
lst = lst + ['new entry']
print(lst) # ['Book', 'Pen', 'new entry']
lst = ['Book', 'Pen']
print(lst) # ['Book', 'Pen']
foo(lst)
print(lst) # ['Book', 'Pen']
Haben Sie hier etwas Neues bemerkt? Wenn Sie mit "Nein" antworten, haben Sie Recht. Aber wenn wir irgendwie die Elemente des veränderlichen Objekts beeinflussen, das an die Funktion übergeben wird, werden wir etwas anderes erleben.
def foo(lst):
lst[1] = 'new entry'
print(lst) # ['Book', 'new entry']
lst = ['Book', 'Pen']
print(lst) # ['Book', 'Pen']
foo(lst)
print(lst) # ['Book', 'new entry']
Wie Sie sehen, wurde das Objekt aus dem Parameter
lstnach dem Funktionsaufruf geändert. Dies geschah aufgrund der Tatsache, dass wir mit einem Verweis auf ein in einem Parameter gespeichertes Objekt arbeiten lst. Das Ändern des Inhalts dieses Objekts liegt daher außerhalb des Funktionsumfangs. Sie können dies vermeiden, indem Sie einfach tiefe Kopien solcher Objekte erstellen und diese in die lokalen Variablen der Funktion schreiben.
def foo(lst):
lst = lst[:]
lst[1] = 'new entry'
print(lst) # ['Book', 'new entry']
lst = ['Book', 'Pen']
print(lst) # ['Book', 'Pen']
foo(lst)
print(lst) # ['Book', 'Pen']
Hat dich das noch nicht überrascht? Wenn nicht, möchte ich sicherstellen, dass Sie das, was Sie wissen, überspringen und sofort zu neuem Material für Sie übergehen. Und wenn ja - dann markieren Sie meine Worte, wenn Sie sich mit den Argumenten vertraut machen, werden Sie viel interessantere Dinge lernen.
Folgendes sollten Sie also über Funktionsargumente wissen:
- Die Reihenfolge, in der Positionsargumente an Funktionen übergeben werden.
- Die Reihenfolge, in der benannte Argumente an Funktionen übergeben werden.
- Zuweisen von Standardargumentwerten.
- Organisation der Verarbeitung von Argumentmengen variabler Länge.
- Argumente entpacken.
- Verwenden von Argumenten, die nur über den Namen übergeben werden können (nur Schlüsselwörter).
Schauen wir uns jeden dieser Punkte an.
1. Reihenfolge der Übergabe von Positionsargumenten an Funktionen
Positionsargumente werden von links nach rechts verarbeitet. Das heißt, es stellt sich heraus, dass die Position des an die Funktion übergebenen Arguments in direkter Übereinstimmung mit der Position des Parameters steht, der im Header der Funktion verwendet wurde, als er deklariert wurde.
def foo(d, e, f):
print(d, e, f)
a, b, c = 1, 2, 3
foo(a, b, c) # 1, 2, 3
foo(b, a, c) # 2, 1, 3
foo(c, b, a) # 3, 2, 1
Die Variablen
a, bund chaben die Werte 1, 2 und 3. Diese Variablen die Rolle der Argumente spielen , mit dem die Funktion aufgerufen wird foo. Sie, wenn die Funktion zum ersten Mal, entsprechen die Parameter aufgerufen wird d, eund f. Dieser Mechanismus gilt für fast alle der oben genannten 6 Punkte, die Sie über Funktionsargumente in Python wissen müssen. Die Position des Positionsarguments, das beim Aufruf an die Funktion übergeben wird, spielt eine wichtige Rolle bei der Zuweisung von Werten zu den Funktionsparametern.
2. Reihenfolge der Übergabe benannter Argumente an Funktionen
Benannte Argumente werden an Funktionen übergeben, wobei die Namen dieser Argumente den Namen entsprechen, die ihnen bei der Deklaration der Funktion zugewiesen wurden.
def foo(arg1=0, arg2=0, arg3=0):
print(arg1, arg2, arg3)
a, b, c = 1, 2, 3
foo(a,b,c) # 1 2 3
foo(arg1=a, arg2=b, arg3=c) # 1 2 3
foo(arg3=c, arg2=b, arg1=a) # 1 2 3
foo(arg2=b, arg1=a, arg3=c) # 1 2 3
Wie Sie sehen können, akzeptiert die Funktion
foo3 Argumente. Diese Argumente werden genannt arg1, arg2und arg3. Achten Sie beim Aufrufen der Funktion darauf, wie wir die Position der Argumente ändern. Benannte Argumente werden anders behandelt als Positionsargumente, obwohl das System sie weiterhin von links nach rechts liest. Python berücksichtigt die Namen der Argumente und nicht ihre Positionen, wenn Funktionsparametern entsprechende Werte zugewiesen werden. Infolgedessen stellt sich heraus, dass die Funktion unabhängig von der Position der an sie übergebenen Argumente dasselbe ausgibt. Es ist immer so 1 2 3.
Bitte beachten Sie, dass die in Absatz 1 beschriebenen Mechanismen hier weiterhin funktionieren.
3. Zuweisen von Standardargumentwerten
Standardwerte können benannten Argumenten zugewiesen werden. Wenn Sie diesen Mechanismus in einer Funktion verwenden, werden bestimmte Argumente optional. Die Deklaration solcher Funktionen sieht so aus, wie wir es in Punkt 2 betrachtet haben. Der einzige Unterschied besteht darin, wie diese Funktionen aufgerufen werden.
def foo(arg1=0, arg2=0, arg3=0):
print(arg1, arg2, arg3)
a, b, c = 1, 2, 3
foo(arg1=a) # 1 0 0
foo(arg1=a, arg2=b ) # 1 2 0
foo(arg1=a, arg2=b, arg3=c) # 1 2 3
Bitte beachten Sie, dass in diesem Beispiel nicht alle Argumente an die Funktion übergeben werden, wie in ihrer Deklaration beschrieben. In diesen Fällen werden den entsprechenden Parametern die Standardwerte zugewiesen. Fahren wir mit diesem Beispiel fort:
foo(arg2=b) # 0 2 0
foo(arg2=b, arg3=c ) # 0 2 3
foo(arg3=c) # 0 0 3
foo(arg3=c, arg1=a ) # 1 0 3
Dies sind einfache und unkomplizierte Beispiele für die Verwendung der oben beschriebenen Mechanismen zum Aufrufen von Funktionen mit der Übergabe benannter Argumente. Lassen Sie uns nun unsere Experimente komplizieren, indem wir das kombinieren, worüber wir bisher in den Punkten 1, 2 und 3 gesprochen haben:
foo(a, arg2=b) # 1 2 0
foo(a, arg2=b, arg3=c) # 1 2 3
foo(a, b, arg3=c) # 1 2 3
foo(a) # 1 0 0
foo(a,b) # 1 2 0
Hier werden beim Aufrufen der Funktion sowohl positionelle als auch benannte Argumente verwendet. Bei Verwendung von Positionsargumenten spielt die Reihenfolge, in der sie angegeben werden, weiterhin eine entscheidende Rolle bei der korrekten Übergabe der Eingabe an die Funktion.
Hier möchte ich Ihre Aufmerksamkeit auf ein bemerkenswertes Detail lenken. Es besteht darin, dass Positionsargumente nicht nach benannten Argumenten angegeben werden können. Hier ist ein Beispiel, das Ihnen hilft, diese Idee besser zu verstehen:
foo(arg1=a, b)
>>>
foo(arg1=a, b)
^
SyntaxError: positional argument follows keyword argument
foo(a, arg2=b, c)
>>>
foo(a, arg2=b, c)
^
SyntaxError: positional argument follows keyword argument
Sie können es in der Regel nehmen. Positionsargumente müssen beim Aufrufen einer Funktion nicht auf benannte Argumente folgen.
4. Organisation der Verarbeitung von Argumentmengen variabler Länge
Hier werden wir über Konstruktionen sprechen
*argsund **kwargs. Wenn diese Konstrukte in einer Funktionsdeklaration verwendet werden, erwarten wir, dass beim Aufruf der Funktion Argumentmengen beliebiger Länge als Parameter argsund dargestellt werden kwargs. Wenn das Konstrukt angewendet wird *args, argsempfängt der Parameter Positionsargumente, die als Tupel dargestellt werden. Bei Anwendung **kwargsim kwargsHerbst benannte Argumente, die in einem Wörterbuch aufgelistet sind.
def foo(*args):
print(args)
a, b, c = 1, 2, 3
foo(a, b, c) # (1, 2, 3)
foo(a, b) # (1, 2)
foo(a) # (1)
foo(b, c) # (2, 3)
Dieser Code beweist, dass der Parameter
argsein Tupel speichert, das enthält, was beim Aufruf an die Funktion übergeben wurde.
def foo(**kwargs):
print(kwargs)
foo(a=1, b=2, c=3) # {'a': 1, 'b': 2, 'c': 3}
foo(a=1, b=2) # {'a': 1, 'b': 2}
foo(a=1) # {'a': 1}
foo(b=2, c=3) # {'b': 2, 'c': 3}
Der obige Code zeigt, dass der Parameter
kwargsein Wörterbuch von Schlüssel-Wert-Paaren speichert, die die benannten Argumente darstellen, die beim Aufruf an die Funktion übergeben werden.
Es ist jedoch zu beachten, dass eine Funktion zum Akzeptieren von Positionsargumenten nicht mit benannten Argumenten übergeben werden kann (und umgekehrt).
def foo(*args):
print(args)
foo(a=1, b=2, c=3)
>>>
foo(a=1, b=2, c=3)
TypeError: foo() got an unexpected keyword argument 'a'
#########################################################
def foo(**kwargs):
print(kwargs)
a, b, c = 1, 2, 3
foo(a, b, c)
>>>
TypeError: foo() takes 0 positional arguments but 3 were given
Lassen Sie uns nun alles zusammenstellen, was wir in den Punkten 1, 2, 3 und 4 analysiert haben, und mit all dem experimentieren und verschiedene Kombinationen von Argumenten untersuchen, die an Funktionen übergeben werden können, wenn sie aufgerufen werden.
def foo(*args,**kwargs):
print(args, kwargs)
foo(a=1,)
# () {'a': 1}
foo(a=1, b=2, c=3)
# () {'a': 1, 'b': 2, 'c': 3}
foo(1, 2, a=1, b=2)
# (1, 2) {'a': 1, 'b': 2}
foo(1, 2)
# (1, 2) {}
Wie Sie sehen, verfügen wir über ein Tupel
argsund ein Wörterbuch kwargs.
Und hier ist eine andere Regel. Es liegt in der Tatsache, dass die Struktur
*argsnicht nach der Struktur verwendet werden kann **kwargs.
def foo(**kwargs, *args):
print(kwargs, args)
>>>
def foo(**kwargs, *args):
^
SyntaxError: invalid syntax
Die gleiche Regel gilt für die Reihenfolge, in der beim Aufruf von Funktionen Argumente angegeben werden. Positionsargumente dürfen nicht auf benannte Argumente folgen.
foo(a=1, 1)
>>>
foo(a=1, 1)
^
SyntaxError: positional argument follows keyword argument
foo(1, a=1, 2)
>>>
foo(1, a=1, 2)
^
SyntaxError: positional argument follows keyword argument
Wenn Funktionen deklarieren, können Sie Positionsargumente kombinieren,
*argsund *kwagrswie folgt dar :
def foo(var, *args,**kwargs):
print(var, args, kwargs)
foo(1, a=1,) # 1
# 1 () {'a': 1}
foo(1, a=1, b=2, c=3) # 2
# 1 () {'a': 1, 'b': 2, 'c': 3}
foo(1, 2, a=1, b=2) # 3
# 1 (2,) {'a': 1, 'b': 2}
foo(1, 2, 3, a=1, b=2) # 4
# 1 (2, 3) {'a': 1, 'b': 2}
foo(1, 2) # 5
# 1 (2,) {}
Bei der Deklaration einer Funktion haben
foowir angenommen, dass sie ein erforderliches Positionsargument haben muss. Es folgt eine Reihe von Positionsargumenten mit variabler Länge, und auf diese Menge folgt eine Reihe von Argumenten mit variabler Länge. Wenn wir dies wissen, können wir jeden der oben genannten Funktionsaufrufe leicht "entschlüsseln".
Der
1Funktion werden Argumente 1und übergeben a=1. Dies sind jeweils positionelle und benannte Argumente. 2Ist eine Sorte 1. Hier ist die Länge des Satzes von Positionsargumenten Null.
In
3passieren wir Funktionen 1, 2und a=1,b=2. Dies bedeutet, dass jetzt zwei Positionsargumente und zwei benannte Argumente akzeptiert werden. Laut Funktionsdeklaration stellt sich heraus, dass1Wird als erforderliches Positionsargument verwendet, 2geht in eine Reihe von Positionsargumenten variabler Länge über a=1und b=2endet in einer Reihe von Argumenten mit variabler Länge.
Um diese Funktion korrekt aufzurufen, müssen wir ihr mindestens ein Positionsargument übergeben. Andernfalls tritt ein Fehler auf.
def foo(var, *args,**kwargs):
print(var, args, kwargs)
foo(a=1)
>>>
foo(a=1)
TypeError: foo() missing 1 required positional argument: 'var'
Eine weitere Variante dieser Funktion ist eine Funktion, die deklariert, dass ein erforderliches Positionsargument und ein benanntes Argument erforderlich sind, gefolgt von Sätzen von Positions- und benannten Argumenten variabler Länge.
def foo(var, kvar=0, *args,**kwargs):
print(var, kvar, args, kwargs)
foo(1, a=1,) # 1
# 1 0 () {'a': 1}
foo(1, 2, a=1, b=2, c=3) # 2
# 1 0 () {'a': 1, 'b': 2, 'c': 3}
foo(1, 2, 3, a=1, b=2) # 3
# 1 2 () {'a': 1, 'b': 2}
foo(1, 2, 3, 4, a=1, b=2) # 4
# 1 2 (3,) {'a': 1, 'b': 2}
foo(1, kvar=2) # 5
# 1 2 () {}
Aufrufe dieser Funktion können auf die gleiche Weise "entschlüsselt" werden, wie dies bei der Analyse der vorherigen Funktion der Fall war.
Beim Aufruf dieser Funktion muss mindestens ein Positionsargument übergeben werden. Andernfalls tritt ein Fehler auf:
foo()
>>>
foo()
TypeError: foo() missing 1 required positional argument: 'var'
foo(1)
# 1 0 () {}
Bitte beachten Sie, dass der Anruf einwandfrei
foo(1)funktioniert. Der Punkt hier ist, dass, wenn eine Funktion aufgerufen wird, ohne einen Wert für ein benanntes Argument anzugeben, der Wert automatisch zugewiesen wird.
Und hier sind einige weitere Fehler, die auftreten können, wenn diese Funktion falsch aufgerufen wird:
foo(kvar=1) # 1
>>>
TypeError: foo() missing 1 required positional argument: 'var'
foo(kvar=1, 1, a=1) # 2
>>>
SyntaxError: positional argument follows keyword argument
foo(1, kvar=2, 3, a=2) # 3
>>>
SyntaxError: positional argument follows keyword argument
Achten Sie besonders auf den Laufzeitfehler
3.
5. Argumente entpacken
In den vorherigen Abschnitten haben wir darüber gesprochen, wie Sätze von Argumenten, die an Funktionen übergeben wurden, in Tupeln und Wörterbüchern gesammelt werden. Und hier werden wir die umgekehrte Operation diskutieren. Wir werden nämlich den Mechanismus analysieren, mit dem Sie die für die Funktionseingabe angegebenen Argumente entpacken können.
args = (1, 2, 3, 4)
print(*args) # 1 2 3 4
print(args) # (1, 2, 3, 4)
kwargs = { 'a':1, 'b':2}
print(kwargs) # {'a': 1, 'b': 2}
print(*kwargs) # a b
Sie können Variablen mit der Syntax
*und entpacken **. Auf diese Weise werden sie verwendet, wenn Tupel, Listen und Wörterbücher an eine Funktion übergeben werden.
def foo(a, b=0, *args, **kwargs):
print(a, b, args, kwargs)
tup = (1, 2, 3, 4)
lst = [1, 2, 3, 4]
d = {'e':1, 'f':2, 'g':'3'}
foo(*tup) # foo(1, 2, 3, 4)
# 1 2 (3, 4) {}
foo(*lst) # foo(1, 2, 3, 4)
# 1 2 (3, 4) {}
foo(1, *tup) # foo(1, 1, 2, 3, 4)
# 1 1 (2, 3, 4) {}
foo(1, 5, *tup) # foo(1, 5, 1, 2, 3, 4)
# 1 5 (1, 2, 3, 4) {}
foo(1, *tup, **d) # foo(1, 1, 2, 3, 4 ,e=1 ,f=2, g=3)
# 1 1 (2, 3, 4) {'e': 1, 'f': 2, 'g': '3'}
foo(*tup, **d) # foo(1, 1, 2, 3, 4 ,e=1 ,f=2, g=3)
# 1 2 (3, 4) {'e': 1, 'f': 2, 'g': '3'}
d['b'] = 45
foo(2, **d) # foo(1, e=1 ,f=2, g=3, b=45)
# 2 45 () {'e': 1, 'f': 2, 'g': '3'}
Dekonstruieren Sie jeden der hier gezeigten Funktionsaufrufe mit dem Entpacken von Argumenten und beachten Sie, wie die entsprechenden Aufrufe ohne
*und aussehen würden **. Versuchen Sie zu verstehen, was passiert, wenn Sie diese Aufrufe tätigen und wie die verschiedenen Datenstrukturen entpackt werden.
Beim Experimentieren mit dem Entpacken von Argumenten kann ein neuer Fehler auftreten:
foo(1, *tup, b=5)
>>>
TypeError: foo() got multiple values for argument 'b'
foo(1, b=5, *tup)
>>>
TypeError: foo() got multiple values for argument 'b'
Dieser Fehler tritt aufgrund eines Konflikts zwischen dem benannten Argument
b=5und dem Positionsargument auf. Wie wir in Abschnitt 2 herausgefunden haben, spielt die Reihenfolge der benannten Argumente bei der Übergabe keine Rolle. Infolgedessen tritt in beiden Fällen der gleiche Fehler auf.
6. Verwenden von Argumenten, die nur mit Namen übergeben werden können (nur Schlüsselwörter)
In einigen Fällen muss die Funktion die erforderlichen benannten Argumente akzeptieren. Wenn sie beim Deklarieren einer Funktion Argumente beschreiben, die nur mit Namen übergeben werden können, müssen solche Argumente bei jedem Aufruf an sie übergeben werden.
def foo(a, *args, b):
print(a, args, b)
tup = (1, 2, 3, 4)
foo(*tup, b=35)
# 1 (2, 3, 4) 35
foo(1, *tup, b=35)
# 1 (1, 2, 3, 4) 35
foo(1, 5, *tup, b=35)
# 1 (5, 1, 2, 3, 4) 35
foo(1, *tup, b=35)
# 1 (1, 2, 3, 4) 35
foo(1, b=35)
# 1 () 35
foo(1, 2, b=35)
# 1 (2,) 35
foo(1)
# TypeError: foo() missing 1 required keyword-only argument: 'b'
foo(1, 2, 3)
# TypeError: foo() missing 1 required keyword-only argument: 'b'
Wie Sie sehen können, wird erwartet, dass der Funktion notwendigerweise ein benanntes Argument übergeben wird
b, das in der Funktionsdeklaration nach angegeben wird *args. In diesem Fall können Sie in der Funktionsdeklaration einfach ein Symbol verwenden. *Danach gibt es durch Kommas getrennte Bezeichner benannter Argumente, die nur über den Namen an die Funktion übergeben werden können. Eine solche Funktion wäre nicht dafür ausgelegt, einen Satz von Positionsargumenten variabler Länge zu akzeptieren.
def foo(a, *, b, c):
print(a, b, c)
tup = (1, 2, 3, 4)
foo(1, b=35, c=55)
# 1 35 55
foo(c= 55, b=35, a=1)
# 1 35 55
foo(1, 2, 3)
# TypeError: foo() takes 1 positional argument but 3 were given
foo(*tup, b=35)
# TypeError: foo() takes 1 positional argument but 4 positional arguments (and 1 keyword-only argument) were given
foo(1, b=35)
# TypeError: foo() takes 1 positional argument but 4 positional arguments (and 1 keyword-only argument) were given
Die im vorherigen Beispiel deklarierte Funktion verwendet ein Positionsargument und zwei benannte Argumente, die nur mit Namen übergeben werden können. Dies führt dazu, dass eine Funktion, um korrekt aufgerufen zu werden, beide benannten Argumente übergeben muss. Danach können
*Sie auch die benannten Argumente beschreiben, denen die Standardwerte zugewiesen werden. Dies gibt uns ein gewisses Maß an Freiheit beim Aufrufen solcher Funktionen.
def foo(a, *, b=0, c, d=0):
print(a, b, c, d)
foo(1, c=55)
# 1 0 55 0
foo(1, c=55, b=35)
# 1 35 55 0
foo(1)
# TypeError: foo() missing 1 required keyword-only argument: 'c'
Beachten Sie, dass die Funktion normal aufgerufen werden kann, ohne dass Argumente an sie übergeben werden
bund dweil sie Standardwerte haben.
Ergebnis
Vielleicht haben wir tatsächlich eine sehr lange Geschichte über Argumente. Ich hoffe, die Leser dieses Materials haben etwas Neues für sich gelernt. Übrigens geht die Geschichte der Funktionsargumente in Python weiter. Vielleicht werden wir später darüber sprechen.
Haben Sie aus diesem Material etwas Neues über Funktionsargumente in Python gelernt?
