3366 Stimmen

Was bewirken ** (Doppelstern/Ostern) und * (Stern/Ostern) bei Parametern?

Was tun *args y **kwargs bedeuten?

def foo(x, y, *args):
def bar(x, y, **kwargs):

14 Stimmen

161 Stimmen

Diese Frage ist ein sehr beliebtes Ziel für Duplikate, aber leider wird sie oft falsch verwendet. Denken Sie daran, dass diese Frage nach folgenden Punkten fragt Funktionen mit Varargs definieren ( def func(*args) ). Für die Frage, was es in der Funktion bedeutet ruft auf. ( func(*[1,2]) ) siehe aquí . Bei einer Frage, die comment zum Entpacken von Argumentlisten siehe aquí . Für eine Frage, die fragt, was die * bedeutet in Literale ( [*[1, 2]] ) siehe aquí .

4 Stimmen

@Aran-Fey: Ich denke, ein besseres Ziel für "was bedeutet es in Funktionsaufrufen" ist Was bedeutet der Sternoperator in einem Funktionsaufruf? . Ihr Link geht nicht wirklich auf die Verwendung von ** und es ist eine viel engere Frage.

3206voto

Peter Hoffmann Punkte 52200

El *args y **kwargs ist ein gängiges Idiom, um eine beliebige Anzahl von Argumenten für Funktionen zuzulassen, wie im Abschnitt mehr zur Definition von Funktionen in der Python-Dokumentation.

El *args gibt Ihnen alle Funktionsparameter als ein Tupel :

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

El **kwargs wird dir alles geben Schlüsselwortargumente mit Ausnahme derjenigen, die einem formalen Parameter wie einem Wörterbuch entsprechen.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name='one', age=27)
# name one
# age 27

Beide Idiome können mit normalen Argumenten gemischt werden, um eine Reihe von festen und einigen variablen Argumenten zu ermöglichen:

def foo(kind, *args, **kwargs):
   pass

Es ist auch möglich, dies andersherum zu verwenden:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

Eine weitere Verwendung des *l Die Redewendung ist zu Argumentlisten auspacken beim Aufruf einer Funktion.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

In Python 3 ist es möglich, mit *l auf der linken Seite einer Zuweisung ( Erweitertes iteratives Entpacken ), obwohl es in diesem Zusammenhang eine Liste statt eines Tupels ergibt:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Auch Python 3 fügt neue semantische (siehe PEP 3102 ):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Eine solche Funktion akzeptiert nur 3 Positionsargumente, und alles nach * können nur als Schlüsselwortargumente übergeben werden.

Nota:

  • Eine Python dict die semantisch für die Übergabe von Schlüsselwortargumenten verwendet werden, sind beliebig geordnet. In Python 3.6 wird jedoch garantiert, dass sich Schlüsselwortargumente an die Einfügereihenfolge erinnern.
  • "Die Reihenfolge der Elemente in **kwargs entspricht nun der Reihenfolge, in der die Schlüsselwortargumente an die Funktion übergeben wurden." - Was ist neu in Python 3.6
  • Tatsächlich merken sich alle Dicts in CPython 3.6 die Einfügereihenfolge als Implementierungsdetail, dies wird in Python 3.7 Standard.

825voto

Lorin Hochstein Punkte 54274

Es ist auch erwähnenswert, dass Sie mit * y ** auch beim Aufruf von Funktionen. Dies ist eine Abkürzung, mit der Sie mehrere Argumente direkt an eine Funktion übergeben können, indem Sie entweder eine Liste/ein Tupel oder ein Wörterbuch verwenden. Wenn Sie zum Beispiel die folgende Funktion haben:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Sie können Dinge tun wie:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Hinweis: Die Tasten in mydict müssen genauso benannt werden wie die Parameter der Funktion foo . Andernfalls kommt es zu einem TypeError :

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'

219voto

nickd Punkte 3741

Der einzelne * bedeutet, dass es eine beliebige Anzahl von zusätzlichen Positionsargumenten geben kann. foo() kann wie folgt aufgerufen werden foo(1,2,3,4,5) . Im Körper von foo() ist param2 eine Sequenz mit 2-5.

Das doppelte ** bedeutet, dass es eine beliebige Anzahl von zusätzlichen benannten Parametern geben kann. bar() kann wie folgt aufgerufen werden bar(1, a=2, b=3) . Im Hauptteil von bar() ist param2 ein Wörterbuch mit {'a':2, 'b':3 }

Mit dem folgenden Code:

def foo(param1, *param2):
    print(param1)
    print(param2)

def bar(param1, **param2):
    print(param1)
    print(param2)

foo(1,2,3,4,5)
bar(1,a=2,b=3)

die Ausgabe ist

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}

213voto

Was bedeutet ** (Doppelstern) und * (star) für Parameter tun?

Sie ermöglichen zu definierende Funktionen zur Annahme von und für Benutzer zu passieren eine beliebige Anzahl von Argumenten, Positionsangaben ( * ) und Schlüsselwort ( ** ).

Definieren von Funktionen

*args erlaubt eine beliebige Anzahl von optionalen Positionsargumenten (Parametern), die einem Tupel namens args .

**kwargs erlaubt eine beliebige Anzahl von optionalen Schlüsselwortargumenten (Parametern), die in einem Diktat namens kwargs .

Sie können (und sollten) jeden geeigneten Namen wählen, aber wenn die Absicht ist, dass die Argumente eine unspezifische Semantik haben sollen, args y kwargs sind Standardnamen.

Erweiterung, Übergabe einer beliebigen Anzahl von Argumenten

Sie können auch Folgendes verwenden *args y **kwargs um Parameter von Listen (oder beliebigen Iterablen) bzw. Dicts (oder beliebigen Zuordnungen) zu übergeben.

Die Funktion, die die Parameter empfängt, muss nicht wissen, dass sie erweitert werden.

Python 2's xrange erwartet zum Beispiel nicht explizit *args aber da es 3 ganze Zahlen als Argumente benötigt:

>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)

Als weiteres Beispiel können wir die dict-Erweiterung in str.format :

>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'

Neu in Python 3: Definieren von Funktionen mit Schlüsselwortargumenten

Sie können haben nur Schlüsselwortargumente nach dem *args - zum Beispiel hier, kwarg2 muss als Schlüsselwortargument angegeben werden - nicht an der Position:

def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs

Verwendung:

>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})

Auch, * kann selbst verwendet werden, um anzuzeigen, dass nur Schlüsselwortargumente folgen, ohne dass unbegrenzte Positionsargumente zulässig sind.

def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs

Ici, kwarg2 muss wiederum ein explizit benanntes Schlüsselwortargument sein:

>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})

Und wir können nicht mehr unbegrenzt Positionsargumente akzeptieren, weil wir nicht über *args* :

>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given

Noch einfacher ausgedrückt, benötigen wir hier kwarg namentlich zu benennen, nicht positionsbezogen:

def bar(*, kwarg=None): 
    return kwarg

In diesem Beispiel sehen wir, dass wir, wenn wir versuchen, die kwarg positionieren, erhalten wir einen Fehler:

>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given

Wir müssen explizit die kwarg Parameter als Schlüsselwortargument.

>>> bar(kwarg='kwarg')
'kwarg'

Python 2 kompatible Demos

*args (typischerweise "star-args" genannt) und **kwargs (Sterne können impliziert werden, indem man "kwargs" sagt, aber explizit mit "double-star kwargs") sind gängige Idiome von Python für die Verwendung der * y ** Notation. Diese spezifischen Variablennamen sind nicht erforderlich (z. B. könnten Sie verwenden *foos y **bars ), aber eine Abweichung von den Konventionen wird Ihre Python-Kollegen wahrscheinlich verärgern.

Wir verwenden sie in der Regel, wenn wir nicht wissen, was unsere Funktion erhalten wird oder wie viele Argumente wir übergeben können, und manchmal sogar, wenn die Benennung jeder Variablen separat sehr unübersichtlich und redundant werden würde (aber das ist ein Fall, in dem normalerweise explizit besser ist als implizit).

Beispiel 1

Die folgende Funktion beschreibt, wie sie verwendet werden können, und demonstriert das Verhalten. Beachten Sie den Namen b Argument wird durch das zweite Positionsargument verbraucht, bevor :

def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and any number of unknown positional arguments and keyword arguments after
    '''
    print('a is a required argument, and its value is {0}'.format(a))
    print('b not required, its default value is 10, actual value: {0}'.format(b))
    # we can inspect the unknown arguments we were passed:
    #  - args:
    print('args is of type {0} and length {1}'.format(type(args), len(args)))
    for arg in args:
        print('unknown arg: {0}'.format(arg))
    #  - kwargs:
    print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                        len(kwargs)))
    for kw, arg in kwargs.items():
        print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
    # But we don't have to know anything about them 
    # to pass them to other functions.
    print('Args or kwargs can be passed without knowing what they are.')
    # max can take two or more positional args: max(a, b, c...)
    print('e.g. max(a, b, *args) \n{0}'.format(
      max(a, b, *args))) 
    kweg = 'dict({0})'.format( # named args same as unknown kwargs
      ', '.join('{k}={v}'.format(k=k, v=v) 
                             for k, v in sorted(kwargs.items())))
    print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
      dict(**kwargs), kweg=kweg))

Wir können in der Online-Hilfe nach der Signatur der Funktion suchen, mit help(foo) die uns sagt

foo(a, b=10, *args, **kwargs)

Rufen wir diese Funktion mit foo(1, 2, 3, 4, e=5, f=6, g=7)

der druckt:

a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}

Beispiel 2

Wir können sie auch über eine andere Funktion aufrufen, die wir einfach mit a :

def bar(a):
    b, c, d, e, f = 2, 3, 4, 5, 6
    # dumping every local variable into foo as a keyword argument 
    # by expanding the locals dict:
    foo(**locals()) 

bar(100) Drucke:

a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}

Beispiel 3: Praktische Anwendung in Dekoratoren

OK, vielleicht sehen wir den Nutzen also noch nicht. Stellen Sie sich also vor, Sie haben mehrere Funktionen mit redundantem Code vor und/oder nach dem differenzierenden Code. Die folgenden benannten Funktionen sind nur Pseudocode zur Veranschaulichung.

def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

def bar(a, b, c=None, d=0, e=100, f=None):
    preprocess()
    differentiating_process_bar(a,b,c,d,e,f)
    postprocess()

def baz(a, b, c, d, e, f):
    ... and so on

Wir können dies vielleicht anders handhaben, aber wir können sicherlich die Redundanz mit einem Dekorator extrahieren, und so zeigt unser Beispiel unten, wie *args y **kwargs kann sehr nützlich sein:

def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper

Und jetzt kann jede umhüllte Funktion viel knapper geschrieben werden, da wir die Redundanz ausgeklammert haben:

@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)

Und durch die Ausklammerung unseres Codes, der *args y **kwargs ermöglicht, reduzieren wir die Anzahl der Codezeilen, verbessern die Lesbarkeit und die Wartbarkeit und haben einen einzigen kanonischen Ort für die Logik in unserem Programm. Wenn wir irgendeinen Teil dieser Struktur ändern müssen, haben wir eine einzige Stelle, an der wir jede Änderung vornehmen können.

66voto

Karan Ahuja Punkte 1169

Lassen Sie uns zunächst verstehen, was Positionsargumente und Schlüsselwortargumente sind. Im Folgenden finden Sie ein Beispiel für eine Funktionsdefinition mit Positionsbezogene Argumente.

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

Es handelt sich also um eine Funktionsdefinition mit Positionsargumenten. Sie können sie auch mit Schlüsselwörtern/benannten Argumenten aufrufen:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3

Betrachten wir nun ein Beispiel für eine Funktionsdefinition mit Schlüsselwortargumente :

def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------

Sie können diese Funktion auch mit Positionsargumenten aufrufen:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

Wir kennen jetzt also Funktionsdefinitionen mit Positions- und Schlüsselwortargumenten.

Betrachten wir nun den '*'- und den '**'-Operator.

Bitte beachten Sie, dass diese Operatoren in 2 Bereichen eingesetzt werden können:

a) Funktionsaufruf

b) Funktionsdefinition

Die Verwendung von "*"- und "**"-Operatoren in Funktionsaufruf.

Lassen Sie uns direkt zu einem Beispiel übergehen und es dann diskutieren.

def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
    print(a+b)

my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}

# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 

# output is 3 in all three calls to sum function.

Denken Sie also daran

wenn der '*'- oder '**'-Operator in einer Datei verwendet wird Funktionsaufruf -

Der Operator '*' entpackt eine Datenstruktur wie eine Liste oder ein Tupel in Argumente, die für die Funktionsdefinition benötigt werden.

Der Operator '**' entpackt ein Wörterbuch in Argumente, die für die Funktionsdefinition benötigt werden.

Betrachten wir nun die Verwendung des Operators '*' in Funktionsdefinition . Beispiel:

def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10

In Funktion Definition der Operator "*" fasst die empfangenen Argumente zu einem Tupel zusammen.

Sehen wir uns nun ein Beispiel für die Verwendung von "**" in der Funktionsdefinition an:

def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum

In Funktion Definition Der '**'-Operator packt die empfangenen Argumente in ein Wörterbuch.

Denken Sie also daran:

In einem Funktionsaufruf der "* packt aus Datenstruktur von Tupel oder Liste in Positions- oder Schlüsselwortargumente, die von der Funktionsdefinition empfangen werden.

In einem Funktionsaufruf die "** packt aus Datenstruktur des Wörterbuchs in Positions- oder Schlüsselwortargumente, die von der Funktionsdefinition empfangen werden.

In einem Funktionsdefinition der "* Packungen positionale Argumente in ein Tupel.

In einem Funktionsdefinition die "** Packungen Schlüsselwortargumente in ein Wörterbuch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X