Was tun ** (Doppelstern/Stern) und * (Stern/Stern) für Parameter in Python?

Lesezeit: 15 Minuten

Benutzeravatar von Todd
Todd

Was tun *args und **kwargs bedeuten?

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

  • siehe auch stackoverflow.com/questions/6967632/…

    – Russland muss Putin entfernen

    1. März 2018 um 20:53 Uhr


  • Diese Frage ist ein sehr beliebtes Duplikatziel, wird aber leider oft falsch verwendet. Denken Sie daran, dass diese Frage nach ungefähr fragt Definieren von Funktionen mit varargs (def func(*args)). Für eine Frage, was es in Funktion bedeutet Anrufe (func(*[1,2])) siehe hier. Für eine Fragestellung wie zum Entpacken von Argumentlisten siehe hier. Für eine Frage, was die * bedeutet hinein Literale ([*[1, 2]]) siehe hier.

    – Aran-Fey

    22. März 2019 um 20:40 Uhr


  • @Aran-Fey: Ich denke, ein besseres Ziel für “was bedeutet es in Funktionsaufrufen” ist Was bedeutet der Sternoperator in einem Funktionsaufruf?. Ihr Link befasst sich nicht wirklich mit der Verwendung von **und es ist eine viel engere Frage.

    – ShadowRanger

    10. Dezember 2020 um 5:55 Uhr

  • Diese Frage ist – wie viele sehr alte Fragen – irgendwie rückwärts gerichtet; Normalerweise sollte sich eine Frage darauf beziehen, wie man ein Problem in neuem Code löst, und nicht, wie man bestehenden Code versteht. Wenn Sie für letzteres etwas anderes als Duplikat schließen, ziehen Sie stackoverflow.com/questions/1993727/… in Betracht (obwohl dies nur für * und nicht **).

    – Karl Knechtel

    17. April um 4:51

  • stackoverflow.com/questions/3394835/use-of-args-and-kwargs wurde ebenfalls als Duplikat davon geschlossen, aber Sie finden es vielleicht besser als dieses.

    – Karl Knechtel

    21. Juni um 3:31 Uhr

Benutzeravatar von Peter Hoffmann
Peter Hofmann

Das *args und **kwargs ist eine gebräuchliche Redewendung, um eine beliebige Anzahl von Argumenten für Funktionen zuzulassen, wie im Abschnitt beschrieben mehr zum Definieren von Funktionen in der Python-Dokumentation.

Das *args gibt Ihnen alle Funktionsparameter als Tupel:

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

foo(1)
# 1

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

Das **kwargs wird dir alles geben
Schlüsselwortargumente außer denen, 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 Redewendungen 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 umgekehrt 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 Redewendung ist zu Argumentlisten entpacken beim Aufruf einer Funktion.

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

l = [1,2]

foo(*l)
# 1 2

In Python 3 ist die Verwendung möglich *l auf der linken Seite einer Zuweisung (Erweitertes iterables Entpacken), obwohl es in diesem Zusammenhang eine Liste anstelle eines Tupels gibt:

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

Auch Python 3 fügt neue Semantik hinzu (vgl PEP 3102):

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

Folgendes funktioniert beispielsweise in Python 3, aber nicht in Python 2:

>>> x = [1, 2]
>>> [*x]
[1, 2]
>>> [*x, 3, 4]
[1, 2, 3, 4]

>>> x = {1:1, 2:2}
>>> x
{1: 1, 2: 2}
>>> {**x, 3:3, 4:4}
{1: 1, 2: 2, 3: 3, 4: 4}

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

Notiz:

  • Eine Python dict, die semantisch für die Übergabe von Schlüsselwortargumenten verwendet werden, sind willkürlich angeordnet. In Python 3.6 merken sich Schlüsselwortargumente jedoch garantiert die Einfügungsreihenfolge.
  • “Die Reihenfolge der Elemente in **kwargs entspricht jetzt der Reihenfolge, in der Schlüsselwortargumente an die Funktion übergeben wurden.” – Was ist neu in Python 3.6
  • Tatsächlich erinnern sich alle Diktate in CPython 3.6 an die Einfügungsreihenfolge als Implementierungsdetail, dies wird in Python 3.7 zum Standard.

Benutzeravatar von Lorin Hochstein
Lorin Hochstein

Es ist auch erwähnenswert, dass Sie verwenden können * und ** 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 beispielsweise 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 Schlüssel in mydict müssen genau wie die Parameter der Funktion benannt werden foo. Andernfalls wirft es a 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'

Benutzeravatar von nickd
nickd

Das einzelne * bedeutet, dass es beliebig viele zusätzliche Positionsargumente geben kann. foo() kann wie aufgerufen werden foo(1,2,3,4,5). Im Hauptteil von foo() ist param2 eine Sequenz, die 2-5 enthält.

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

Mit folgendem 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}

Russland muss Putins Benutzer-Avatar entfernen
Russland muss Putin entfernen

Was macht ** (Doppelstern) und * (Stern) tun für Parameter?

Sie ermöglichen Funktionen, die definiert werden müssen, um akzeptiert zu werden und für Benutzer zu passieren beliebig viele Argumente, positional (*) und Schlüsselwort (**).

Funktionen definieren

*args erlaubt eine beliebige Anzahl optionaler Positionsargumente (Parameter), die einem Tupel namens zugewiesen werden args.

**kwargs erlaubt eine beliebige Anzahl optionaler Schlüsselwortargumente (Parameter), die in einem Diktat mit dem Namen enthalten sind kwargs.

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

Erweiterung, Übergabe einer beliebigen Anzahl von Argumenten

Sie können auch verwenden *args und **kwargs um Parameter aus Listen (oder iterierbaren) bzw. Diktaten (oder beliebigen Mappings) zu übergeben.

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

Zum Beispiel erwartet xrange von Python 2 nicht explizit *argsaber da es 3 ganze Zahlen als Argumente braucht:

>>> 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 verwenden 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 nur mit Schlüsselwortargumenten

Du kannst haben Schlüsselwort nur Argumente nach dem *args – z.B. hier kwarg2 muss als Schlüsselwortargument angegeben werden – nicht positionell:

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

Verwendungszweck:

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

Ebenfalls, * kann allein verwendet werden, um anzugeben, dass nur Schlüsselwortargumente folgen, ohne unbegrenzte Positionsargumente zuzulassen.

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

Hier, kwarg2 muss wieder 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 länger unbegrenzte Positionsargumente akzeptieren, weil wir sie nicht haben *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, hier verlangen wir kwarg namentlich anzugeben, nicht positionell:

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

In diesem Beispiel sehen wir das, wenn wir versuchen zu passen kwarg positionell 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 die ausdrücklich übergeben kwarg Parameter als Schlüsselwortargument.

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

Python 2-kompatible Demos

*args (normalerweise “Star-Argumente” genannt) und **kwargs (Sterne können impliziert werden, indem man “kwargs” sagt, aber mit “double-star kwargs” explizit sein) sind gängige Redewendungen von Python für die Verwendung von * und ** Notation. Diese spezifischen Variablennamen sind nicht erforderlich (z. B. könnten Sie verwenden *foos und **bars), aber eine Abweichung von der Konvention wird Ihre Python-Programmierer wahrscheinlich verärgern.

Wir verwenden diese normalerweise, wenn wir nicht wissen, was unsere Funktion empfangen wird oder wie viele Argumente wir möglicherweise übergeben, und manchmal würde sogar das separate Benennen jeder Variablen sehr chaotisch und überflüssig (aber dies ist ein Fall, in dem dies normalerweise explizit ist besser als implizit).

Beispiel 1

Die folgende Funktion beschreibt, wie sie verwendet werden können, und demonstriert ihr Verhalten. Beachten Sie die benannten b Das Argument wird vom zweiten Positionsargument vor verbraucht:

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 die Online-Hilfe für die Signatur der Funktion mit überprüfen help(foo)was uns sagt

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

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

was 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 es auch mit einer anderen Funktion aufrufen, die wir gerade bereitstellen 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 Dekorateuren

OK, vielleicht sehen wir das Dienstprogramm 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 zu Veranschaulichungszwecken.

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 die Redundanz sicherlich mit einem Dekorateur extrahieren, und unser Beispiel unten zeigt, wie das geht *args und **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 verpackte Funktion viel prägnanter geschrieben werden, da wir die Redundanz herausgerechnet 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 indem wir unseren Code ausklammern, der *args und **kwargs erlaubt, reduzieren wir Codezeilen, verbessern die Lesbarkeit und Wartbarkeit und haben einzige kanonische Speicherorte für die Logik in unserem Programm. Wenn wir irgendeinen Teil dieser Struktur ändern müssen, haben wir einen Ort, an dem wir jede Änderung vornehmen können.

Benutzeravatar von mrtechmaker
mrtechmaker

Lassen Sie uns zuerst verstehen, was Positionsargumente und Schlüsselwortargumente sind. Unten ist ein Beispiel für die Funktionsdefinition mit Positionale Argumente.

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

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

Das ist also eine Funktionsdefinition mit Positionsargumenten. Sie können es auch mit Schlüsselwort/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

Lassen Sie uns nun ein Beispiel für die Funktionsdefinition mit untersuchen 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 also jetzt Funktionsdefinitionen mit Positions- und Schlüsselwortargumenten.

Lassen Sie uns nun den ‘*’-Operator und den ‘**’-Operator untersuchen.

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

a) Funktionsaufruf

b) Funktionsdefinition

Die Verwendung des ‘*’-Operators und des ‘**’-Operators in Funktionsaufruf.

Kommen wir gleich zu einem Beispiel und diskutieren es dann.

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.

Also denk daran

wenn der Operator ‘*’ oder ‘**’ in a verwendet wird Funktionsaufruf

Der Operator ‘*’ entpackt eine Datenstruktur wie eine Liste oder ein Tupel in Argumente, die von der Funktionsdefinition benötigt werden.

Der ‘**’-Operator entpackt ein Wörterbuch in Argumente, die von der Funktionsdefinition benötigt werden.

Lassen Sie uns nun den ‘*’-Operator untersuchen, der in verwendet wird 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 packt die empfangenen Argumente in ein Tupel.

Sehen wir uns nun ein Beispiel für ‘**’ an, das in der Funktionsdefinition verwendet wird:

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 Dictionary.

Also denk daran:

In einem Funktionsaufruf das ‘*’ auspackt Datenstruktur eines Tupels oder einer Liste in Positions- oder Schlüsselwortargumente, die von der Funktionsdefinition empfangen werden sollen.

In einem Funktionsaufruf das ‘**’ auspackt Datenstruktur des Wörterbuchs in Positions- oder Schlüsselwortargumente, die von der Funktionsdefinition empfangen werden sollen.

In einem Funktionsdefinition das ‘*’ Packungen Positionsargumente in ein Tupel.

In einem Funktionsdefinition das ‘**’ Packungen Schlüsselwortargumente in ein Wörterbuch.

Diese Tabelle ist praktisch für die Verwendung * und ** in Funktion Konstruktion und Funktion Anruf:

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

Dies dient wirklich nur dazu, Lorin Hochsteins Antwort zusammenzufassen, aber ich finde es hilfreich.

Verwandte: Verwendungen für die Stern-/Splat-Operatoren waren erweitert in Python3

Benutzeravatar von Bill the Lizard
Bill die Eidechse

* und ** haben eine besondere Verwendung in der Liste der Funktionsargumente. *
impliziert, dass das Argument eine Liste und ist ** impliziert, dass das Argument ein Wörterbuch ist. Dadurch können Funktionen eine beliebige Anzahl von Argumenten annehmen

1433290cookie-checkWas tun ** (Doppelstern/Stern) und * (Stern/Stern) für Parameter in Python?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy