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


In den folgenden Methodendefinitionen, was macht die * und ** tun für param2?

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

1574
2017-08-31 15:04


Ursprung


Antworten:


Das *args und **kwargs ist ein allgemeines Idiom, um eine beliebige Anzahl von Argumenten für Funktionen zuzulassen, wie im Abschnitt beschrieben mehr über das Definieren von Funktionen in der Python-Dokumentation.

Das *args gibt Ihnen alle Funktionsparameter als Tupel:

In [1]: def foo(*args):
   ...:     for a in args:
   ...:         print a
   ...:         
   ...:         

In [2]: foo(1)
1


In [4]: foo(1,2,3)
1
2
3

Das **kwargs Ich werde dir alles geben Schlüsselwortargumente außer denen, die einem formalen Parameter als Wörterbuch entsprechen.

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

In [6]: bar(name='one', age=27)
age 27
name one

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

Eine andere Verwendung der *l Idiom ist zu Entpacke die Argumentlisten wenn eine Funktion aufgerufen wird.

In [9]: def foo(bar, lee):
   ...:     print bar, lee
   ...:     
   ...:     

In [10]: l = [1,2]

In [11]: foo(*l)
1 2

In Python 3 ist es möglich zu verwenden *l auf der linken Seite einer Aufgabe (Erweitertes Iterables Auspacken), obwohl es in diesem Zusammenhang eine Liste statt 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

Eine solche Funktion akzeptiert nur 3 Positionsargumente und alles danach * kann nur als Schlüsselwortargument übergeben werden.


1550
2017-08-31 15:17



Es ist auch erwähnenswert, dass Sie verwenden können * und ** beim Aufruf von Funktionen auch. Dies ist eine Verknüpfung, mit der Sie mehrere Argumente direkt an eine Funktion übergeben können, indem Sie entweder eine Liste / ein Tupel oder ein Wörterbuch verwenden. Zum Beispiel, wenn Sie 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. Sonst wird es ein werfen 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'

448
2017-08-31 15:47



Die einzige * bedeutet, dass es eine beliebige Anzahl von zusätzlichen Positionsargumenten geben kann. foo() kann wie aufgerufen werden foo(1,2,3,4,5). Im Körper von foo () ist param2 eine Sequenz, die 2-5 enthält.

Das Double ** bedeutet, dass es beliebig viele extra benannte Parameter geben kann. bar() kann wie aufgerufen werden bar(1, a=2, b=3). Im Body von bar () ist param2 ein Wörterbuch mit {'a': 2, 'b': 3}

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}

128
2017-08-31 15:20



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

Sie erlauben zu definierende Funktionen zum Akzeptieren und für Benutzer zu übergeben beliebig viele Argumente, positional (*) und Stichwort (**).

Funktionen definieren

*args ermöglicht eine beliebige Anzahl von optionalen Positionsargumenten (Parametern), die einem Tupel namens zugewiesen werden args.

**kwargs ermöglicht eine beliebige Anzahl von optionalen Schlüsselwortargumenten (Parametern), die in einem Diktat benannt werden kwargs.

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

Erweiterung, Übergeben einer beliebigen Anzahl von Argumenten

Sie können auch verwenden *args und **kwargs um Parameter von Listen (oder irgendwelchen iterierbaren) und dicts (oder irgendeiner Abbildung) zu übergeben.

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

Zum Beispiel erwartet Python 2 xrange 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 ein weiteres Beispiel können wir dict Expansion 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 mit Argumenten nur mit Schlüsselwörtern

Du kannst haben Schlüsselwort nur Argumente nach dem *args - Zum Beispiel hier kwarg2 muss als Schlüsselwortargument angegeben werden - nicht positionsbezogen:

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'})

Ebenfalls, * kann verwendet werden, um anzugeben, dass nur die Argumente des Schlüsselworts folgen, ohne dass unbegrenzte Positionsargumente zulässig sind.

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

Hier, 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 keine unbegrenzten Positionsargumente mehr akzeptieren, weil wir es 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 brauchen wir kwarg Name, nicht positionsbezogen:

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

In diesem Beispiel sehen wir, dass wir versuchen, zu bestehen 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 ausdrücklich die kwarg Parameter als Schlüsselwortargument.

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

Python 2-kompatible Demos

*args (typischerweise "Star-Args") und **kwargs (Sterne können mit "kwargs" impliziert werden, aber mit "double-star kwargs" explizit sein) sind gängige Idiome von Python zur Verwendung der * und ** Notation. Diese spezifischen Variablennamen sind nicht erforderlich (z. B. könnten Sie verwenden *foos und **bars), aber eine Abweichung von der Konvention wird wahrscheinlich Ihre Python-Programmierer verärgern.

Wir verwenden diese normalerweise, wenn wir nicht wissen, was unsere Funktion erhalten wird oder wie viele Argumente wir übergeben, und manchmal sogar wenn jede Variable getrennt benannt wird, würde sie sehr unordentlich und redundant werden (aber dies ist ein Fall, wo es normalerweise explizit ist) besser als implizit).

Beispiel 1

Die folgende Funktion beschreibt, wie sie verwendet werden können, und demonstriert das Verhalten. Beachten Sie den Namen b Das Argument wird vor dem zweiten Positionsargument 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) 

welches 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, in die wir nur liefern 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 Verwendung in Dekorateuren

OK, vielleicht sehen wir das Dienstprogramm noch nicht. Stellen Sie sich vor, Sie haben mehrere Funktionen mit redundantem Code vor und / oder nach dem differenzierenden Code. Die folgenden benannten Funktionen sind nur Pseudo-Code für illustrative Zwecke.

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 vielleicht anders damit umgehen, aber wir können die Redundanz mit einem Decorator sicher extrahieren, und so demonstriert unser Beispiel unten wie *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 eingepackte Funktion viel prägnanter 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 indem wir unseren Code ausschließen, welcher *args und **kwargs ermöglicht es uns, Codezeilen zu reduzieren, die Lesbarkeit und Wartbarkeit zu verbessern und die einzigen kanonischen Orte für die Logik in unserem Programm zu haben. Wenn wir irgendeinen Teil dieser Struktur ändern müssen, haben wir einen Ort, an dem wir jede Veränderung vornehmen können.


105
2017-10-14 16:34



Lassen Sie uns zuerst verstehen, was Positionsargumente und Schlüsselwortargumente sind. Im Folgenden finden Sie ein Beispiel für die Funktionsdefinition mit Positionsargumente

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

Betrachten wir nun ein Beispiel für die 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
---------------------------------

So kennen wir nun Funktionsdefinitionen sowohl mit positionalen als auch mit Schlüsselwortargumenten.

Lassen Sie uns nun den '*' Operator und den '**' Operator studieren.

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

ein) Funktionsaufruf

b) Funktionsdefinition

Die Verwendung von '*' Operator und '**' Operator in Funktionsaufruf 

Lassen Sie uns direkt zu einem Beispiel kommen und diskutieren Sie 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 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 für die Funktionsdefinition benötigt werden.

Lassen Sie uns nun den Operator '*' 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 '*' packt die empfangenen Argumente in ein Tupel.

Sehen wir uns nun ein Beispiel für '**' 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.

Also denk daran:

In einem Funktionsaufruf das '*' packt aus Datenstruktur von Tupel oder Liste in Positions- oder Schlüsselwortargumenten, die von der Funktionsdefinition empfangen werden sollen.

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

In einem Funktionsdefinition das '*' packt Positionsargumente in ein Tupel.

In einem Funktionsdefinition das '**' packt Schlüsselwortargumente in ein Wörterbuch.


37
2018-01-20 11:40



* und ** Besondere Verwendung in der Funktionsargumentliste. * Impliziert, dass das Argument eine Liste ist und ** impliziert das Argument ist ein Wörterbuch. Dies ermöglicht Funktionen eine beliebige Anzahl von zu nehmen Argumente


20
2017-09-11 04:33



Aus der Python-Dokumentation:

Wenn es mehr positionale Argumente als formale Parameter-Slots gibt, wird eine TypeError-Exception ausgelöst, sofern kein formaler Parameter mit der Syntax "* identifier" vorhanden ist. In diesem Fall erhält dieser formale Parameter ein Tupel, das die überflüssigen Positionsargumente enthält (oder ein leeres Tupel, wenn keine übermäßigen Positionsargumente vorhanden waren).

Wenn ein beliebiges Schlüsselwort-Argument keinem formalen Parameternamen entspricht, wird eine TypeError-Ausnahme ausgelöst, sofern kein formaler Parameter mit der Syntax "** identifier" vorhanden ist. In diesem Fall erhält dieser formale Parameter ein Dictionary, das die überflüssigen Schlüsselwortargumente enthält (die Schlüsselwörter als Schlüssel und die Argumentwerte als entsprechende Werte verwenden) oder ein (neues) leeres Dictionary, wenn keine überzähligen Schlüsselwortargumente vorhanden sind.


11
2017-08-31 15:07



Ich möchte ein Beispiel geben, das andere nicht erwähnt haben

* kann auch entpacken Generator

Ein Beispiel aus Python3 Document

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x ist [1, 2, 3], unzip_y ist [4, 5, 6]

Die zip () empfängt mehrere iretable args und gibt einen Generator zurück.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))

7
2017-11-08 16:50



In Python 3.5 können Sie diese Syntax auch in verwenden list, dict, tuple, und set wird angezeigt (manchmal auch als Literale bezeichnet). Sehen PEP 488: Zusätzliche Entpackungsgeneralisierungen.

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

Außerdem können mehrere Iterables in einem einzigen Funktionsaufruf entpackt werden.

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(Danke an mgilson für die PEP-Verbindung.)


6
2017-12-08 21:38



Während Anwendungen für die Stern / Splat-Operatoren waren erweitert In Python 3 gefällt mir die folgende Tabelle in Bezug auf die Verwendung dieser Operatoren mit Funktionen. Die Splat-Operatoren können beide innerhalb der Funktion verwendet werden Konstruktion und in der 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)                   |
-----------------------------------------------------------------------

Das ist wirklich nur eine Zusammenfassung von Lorin Hochsteins Antworten aber ich finde es hilfreich.


6
2017-11-30 18:28