Cosa fanno ** (doppia stella / asterisco) e * (stella / asterisco) per i parametri?


2352

Nelle seguenti definizioni di metodo, a cosa servono *e **cosa fanno param2?

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



Vedi anche stackoverflow.com/questions/14301967/… per un asterisco nudo
naught101

24
Questa domanda è un obiettivo duplicato molto popolare, ma sfortunatamente viene spesso utilizzata in modo errato. Tieni presente che questa domanda pone sulla definizione di funzioni con varargs ( def func(*args)). Per una domanda che chiede cosa significhi nelle chiamate di funzione ( func(*[1,2])) vedere qui . Per una domanda che chiede come decomprimere gli elenchi di argomenti, vedere qui . Per una domanda che chiede cosa *significhi in letterali ( [*[1, 2]]) vedere qui .
Aran-Fey,

Puoi saperne di più sul suo utilizzo nella definizione della funzione e nella chiamata di funzione qui: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Risposte:


2239

Il *argse**kwargs è un linguaggio comune per consentire un numero arbitrario di argomenti alle funzioni come descritto nella sezione più sulla definizione delle funzioni nella documentazione di Python.

Il *argsvi darà tutti i parametri di funzione come una tupla :

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

foo(1)
# 1

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

Il **kwargsvi darà tutti argomenti a parola chiave ad eccezione di quelli corrispondenti ad un parametro formale come un dizionario.

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

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

Entrambi i modi di dire possono essere mescolati con argomenti normali per consentire una serie di argomenti fissi e alcuni variabili:

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

È anche possibile usarlo al contrario:

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

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

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

Un altro uso del *llinguaggio è decomprimere gli elenchi di argomenti quando si chiama una funzione.

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

l = [1,2]

foo(*l)
# 1 2

In Python 3 è possibile utilizzare *lsul lato sinistro di un compito ( Extended Iterable Unpacking ), sebbene fornisca un elenco anziché una tupla in questo contesto:

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

Anche Python 3 aggiunge un nuovo semantico (consultare PEP 3102 ):

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

Tale funzione accetta solo 3 argomenti posizionali e tutto ciò che segue *può essere passato solo come argomenti di parole chiave.


9
L'output di [6] è in ordine inverso. nome un'età di 27 anni
thanos.a

54
@ thanos.a I dicts di Python, usati semanticamente per passare l'argomento delle parole chiave, sono arbitrariamente ordinati. Tuttavia, in Python 3.6, gli argomenti delle parole chiave sono sicuri di ricordare l'ordine di inserimento. "L'ordine degli elementi **kwargsora corrisponde all'ordine in cui gli argomenti delle parole chiave sono stati passati alla funzione." - docs.python.org/3/whatsnew/3.6.html In effetti, tutti i dicts in CPython 3.6 ricorderanno l'ordine di inserimento come dettaglio di implementazione, questo diventa standard in Python 3.7.
Aaron Hall

13
Molto preciso, pulito e facile da capire. Apprezzo che tu abbia notato che si tratta di un "operatore di disimballaggio", in modo da poter differenziare dal passaggio per riferimento in C. +1
bballdave025

Come testare l'ultima funzione con PEP 3102? Lo chiamo con func (1,2,3, name = "me", age = 10) e genera un'eccezione:got an unexpected keyword argument 'name'
Kok How Teh,

@KokHowTeh Devi passare i kwarg nominati come sono nella funzione: func (1, 2, 3, kwarg1 = 'me', kwarg2 = 10)
John Aaron,

622

Vale anche la pena notare che è possibile utilizzare *e anche **quando si chiamano le funzioni. Questa è una scorciatoia che ti consente di passare più argomenti a una funzione direttamente usando un elenco / tupla o un dizionario. Ad esempio, se si dispone della seguente funzione:

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

Puoi fare cose come:

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

Nota: i tasti mydictdevono essere nominati esattamente come i parametri della funzione foo. Altrimenti lancerà un 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'

175

Il singolo * significa che può esserci un numero qualsiasi di argomenti posizionali extra. foo()può essere invocato comefoo(1,2,3,4,5) . Nel corpo di foo () param2 è una sequenza contenente 2-5.

Il doppio ** significa che può esserci un numero qualsiasi di parametri extra nominati. bar()può essere invocato come bar(1, a=2, b=3). Nel corpo di bar () param2 è un dizionario contenente {'a': 2, 'b': 3}

Con il seguente codice:

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)

l'uscita è

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

5
Forse un ulteriore esempio con foobar(param1, *param2, **param3)è necessario per completezza di questa risposta.
Aniket Thakur,

1
@AniketThakur ha aggiunto la parte rimanente qui .
Raj

148

Cosa fanno **(stella doppia) e *(stella) per i parametri

Consentono che le funzioni vengano definite per accettare e che gli utenti passino qualsiasi numero di argomenti, posizionale ( *) e parola chiave ( **).

Definizione delle funzioni

*argsconsente un numero qualsiasi di argomenti posizionali opzionali (parametri), che verranno assegnati a una tupla denominata args.

**kwargsconsente un numero qualsiasi di argomenti di parole chiave opzionali (parametri), che saranno in un dict denominato kwargs.

Puoi (e dovresti) scegliere un nome appropriato, ma se l'intenzione è che gli argomenti siano di semantica non specifica argse kwargssiano nomi standard.

Espansione, passando un numero qualsiasi di argomenti

Puoi anche usare *argse **kwargspassare parametri rispettivamente da liste (o da qualsiasi iterabile) e da dicts (o da qualsiasi mappatura).

La funzione che riceve i parametri non deve sapere che sono in fase di espansione.

Ad esempio, lo xrange di Python 2 non si aspetta esplicitamente *args, ma poiché prende 3 numeri interi come argomenti:

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

Come altro esempio, possiamo usare l'espansione dict in str.format:

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

Novità di Python 3: definizione delle funzioni con argomenti solo per parole chiave

Puoi avere argomenti solo per parole chiave dopo che *args- ad esempio, qui, kwarg2deve essere fornito come argomento per parole chiave - non posizionalmente:

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

Uso:

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

Inoltre, *può essere utilizzato da solo per indicare che seguono solo gli argomenti delle parole chiave, senza consentire argomenti posizionali illimitati.

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

Anche in questo kwarg2caso deve essere un argomento di parole chiave con nome esplicito:

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

E non possiamo più accettare argomenti posizionali illimitati perché non abbiamo *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

Ancora una volta, più semplicemente, qui dobbiamo kwargessere dati per nome, non in posizione:

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

In questo esempio, vediamo che se proviamo a passare in modo kwargposizionale, otteniamo un errore:

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

Dobbiamo passare esplicitamente il kwargparametro come argomento della parola chiave.

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

Demo compatibili con Python 2

*args(in genere detto "star-args") e **kwargs(le stelle possono essere implicite dicendo "kwargs", ma essere esplicito con "kwargs doppia stella") sono idiomi comuni di Python per l'utilizzo del *e **la notazione. Questi nomi di variabili specifici non sono richiesti (ad esempio, è possibile utilizzare*foos e**bars ), ma è probabile che una deviazione dalla convenzione faccia arrabbiare i tuoi colleghi programmatori Python.

Di solito li usiamo quando non sappiamo quale sarà la nostra funzione o quanti argomenti potremmo passare, e talvolta anche quando nominiamo ogni variabile separatamente diventerebbe molto confusa e ridondante (ma questo è un caso in cui di solito esplicito è meglio che implicito).

Esempio 1

La seguente funzione descrive come possono essere utilizzati e illustra il comportamento. Si noti che l' bargomento denominato verrà utilizzato dal secondo argomento posizionale prima di:

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

Possiamo controllare la guida in linea per la firma della funzione, con help(foo), che ci dice

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

Chiamiamo questa funzione con foo(1, 2, 3, 4, e=5, f=6, g=7)

che stampa:

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}

Esempio 2

Possiamo anche chiamarlo usando un'altra funzione, nella quale forniamo semplicemente 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) stampe:

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}

Esempio 3: utilizzo pratico nei decoratori

OK, quindi forse non stiamo ancora vedendo l'utilità. Quindi immagina di avere diverse funzioni con codice ridondante prima e / o dopo il codice di differenziazione. Le seguenti funzioni nominate sono solo pseudo-codice a scopo illustrativo.

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

Potremmo essere in grado di gestirlo in modo diverso, ma possiamo certamente estrarre la ridondanza con un decoratore, quindi il nostro esempio di seguito dimostra come *argse **kwargspuò essere molto utile:

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

E ora ogni funzione avvolta può essere scritta in modo molto più succinto, poiché abbiamo preso in considerazione la ridondanza:

@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)

E prendendo in considerazione il nostro codice, che *argse **kwargsci consente di fare, riduciamo le linee di codice, miglioriamo la leggibilità e la manutenibilità e disponiamo di sole posizioni canoniche per la logica nel nostro programma. Se abbiamo bisogno di cambiare qualsiasi parte di questa struttura, abbiamo un posto in cui effettuare ogni cambiamento.


48

Cerchiamo innanzitutto di capire quali sono gli argomenti posizionali e gli argomenti delle parole chiave. Di seguito è riportato un esempio di definizione della funzione con argomenti posizionali.

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

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

Quindi questa è una definizione di funzione con argomenti posizionali. Puoi chiamarlo anche con argomenti con parole chiave / nominati:

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

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

Ora studiamo un esempio di definizione di funzione con argomenti di parole chiave :

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

Puoi chiamare questa funzione anche con argomenti posizionali:

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

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

Quindi ora conosciamo le definizioni delle funzioni con argomenti posizionali e parole chiave.

Ora studiamo l'operatore '*' e l'operatore '**'.

Si noti che questi operatori possono essere utilizzati in 2 aree:

a) chiamata di funzione

b) definizione della funzione

L'uso dell'operatore '*' e dell'operatore '**' nella chiamata di funzione.

Vediamo subito un esempio e poi discutiamone.

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.

Quindi ricorda

quando l'operatore '*' o '**' viene utilizzato in una chiamata di funzione -

L'operatore '*' decomprime la struttura dei dati come un elenco o una tupla in argomenti necessari per la definizione della funzione.

L'operatore '**' decomprime un dizionario in argomenti necessari per la definizione della funzione.

Ora studiamo l'uso dell'operatore '*' nella definizione della funzione . Esempio:

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

Nella definizione della funzione l'operatore '*' racchiude gli argomenti ricevuti in una tupla.

Vediamo ora un esempio di '**' usato nella definizione della funzione:

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

Nella definizione della funzione L'operatore '**' racchiude gli argomenti ricevuti in un dizionario.

Quindi ricorda:

In una funzione chiamare '*' decomprime la struttura dei dati della tupla o dell'elenco in argomenti posizionali o di parole chiave che devono essere ricevuti dalla definizione della funzione.

In una chiamata di funzione '**' scompone la struttura dei dati del dizionario in argomenti posizionali o di parole chiave che devono essere ricevuti dalla definizione della funzione.

Nella definizione di una funzione '*' racchiude gli argomenti posizionali in una tupla.

Nella definizione di una funzione '**' racchiude gli argomenti delle parole chiave in un dizionario.


Spiegazione davvero pulita, passo dopo passo e facile da seguire!
Aleksandar,

grazie Continuate a ricevere voti. [Anche per ulteriori note da parte mia, sono a @mrtechmaker su Twitter]
Karan Ahuja,

32

Questa tabella è utile per l'uso *e **nella costruzione di funzioni e chiamate di funzioni :

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

Questo serve davvero a riassumere la risposta di Lorin Hochstein ma la trovo utile.

Relativamente: gli usi per gli operatori stella / splat sono stati espansi in Python 3


22

*e **hanno un uso speciale nell'elenco degli argomenti delle funzioni. * implica che l'argomento è un elenco e **implica che l'argomento è un dizionario. Ciò consente alle funzioni di accettare un numero arbitrario di argomenti


17

Per quelli di voi che imparano con esempi!

  1. Lo scopo di * è darti la possibilità di definire una funzione che può prendere un numero arbitrario di argomenti forniti come un elenco (ad esf(*myList) ).
  2. Lo scopo di **è darti la possibilità di alimentare gli argomenti di una funzione fornendo un dizionario (ad es f(**{'x' : 1, 'y' : 2}).).

Cerchiamo di mostrare questo definendo una funzione che prende due variabili normali x, ye può accettare più argomenti myArgs, e può accettare ancora di più argomenti myKW. Più avanti, mostreremo come alimentare yusando myArgDict.

def f(x, y, *myArgs, **myKW):
    print("# x      = {}".format(x))
    print("# y      = {}".format(y))
    print("# myArgs = {}".format(myArgs))
    print("# myKW   = {}".format(myKW))
    print("# ----------------------------------------------------------------------")

# Define a list for demonstration purposes
myList    = ["Left", "Right", "Up", "Down"]
# Define a dictionary for demonstration purposes
myDict    = {"Wubba": "lubba", "Dub": "dub"}
# Define a dictionary to feed y
myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}

# The 1st elem of myList feeds y
f("myEx", *myList, **myDict)
# x      = myEx
# y      = Left
# myArgs = ('Right', 'Up', 'Down')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# y is matched and fed first
# The rest of myArgDict becomes additional arguments feeding myKW
f("myEx", **myArgDict)
# x      = myEx
# y      = Why?
# myArgs = ()
# myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
# ----------------------------------------------------------------------

# The rest of myArgDict becomes additional arguments feeding myArgs
f("myEx", *myArgDict)
# x      = myEx
# y      = y
# myArgs = ('y0', 'q')
# myKW   = {}
# ----------------------------------------------------------------------

# Feed extra arguments manually and append even more from my list
f("myEx", 4, 42, 420, *myList, *myDict, **myDict)
# x      = myEx
# y      = 4
# myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# Without the stars, the entire provided list and dict become x, and y:
f(myList, myDict)
# x      = ['Left', 'Right', 'Up', 'Down']
# y      = {'Wubba': 'lubba', 'Dub': 'dub'}
# myArgs = ()
# myKW   = {}
# ----------------------------------------------------------------------

Avvertenze

  1. ** è riservato esclusivamente ai dizionari.
  2. L'assegnazione dell'argomento non facoltativo viene eseguita per prima.
  3. Non è possibile utilizzare due volte un argomento non facoltativo.
  4. Se applicabile, **deve venire dopo *, sempre.

14

Dalla documentazione di Python:

Se sono presenti più argomenti posizionali di quanti siano gli slot dei parametri formali, viene sollevata un'eccezione TypeError, a meno che non sia presente un parametro formale che utilizza la sintassi "* identificatore"; in questo caso, quel parametro formale riceve una tupla contenente gli argomenti posizionali in eccesso (o una tupla vuota se non c'erano argomenti posizionali in eccesso).

Se un argomento della parola chiave non corrisponde al nome di un parametro formale, viene sollevata un'eccezione TypeError, a meno che non sia presente un parametro formale che utilizza la sintassi "** identificatore"; in questo caso, quel parametro formale riceve un dizionario contenente gli argomenti delle parole chiave in eccesso (usando le parole chiave come chiavi e i valori degli argomenti come valori corrispondenti) o un (nuovo) dizionario vuoto se non c'erano argomenti delle parole chiave in eccesso.


10

* significa ricevere argomenti variabili come tupla

** significa ricevere argomenti variabili come dizionario

Usato come il seguente:

1) singolo *

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

foo("two", 3)

Produzione:

two
3

2) Adesso **

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

bar(dic1="two", dic2=3)

Produzione:

dic1 two
dic2 3

8

Voglio fare un esempio che altri non hanno menzionato

* può anche decomprimere un generatore

Un esempio dal documento Python3

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

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

unzip_x sarà [1, 2, 3], unzip_y sarà [4, 5, 6]

Zip () riceve più argetable args e restituisce un generatore.

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

7

In Python 3.5, è anche possibile utilizzare questa sintassi in list, dict, tuple, e setvisualizza (a volte chiamato anche letterali). Vedere PEP 488: Generalizzazioni aggiuntive sul disimballaggio .

>>> (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}

Inoltre, consente di decomprimere più iterabili in una singola chiamata di funzione.

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

(Grazie a mgilson per il collegamento PEP.)


1
Non sono sicuro che questa sia una violazione di "c'è solo un modo per farlo". Non c'è altro modo per inizializzare un elenco / tupla da più iterabili: al momento è necessario raggrupparli in un unico iterabile che non è sempre conveniente. Puoi leggere informazioni sul razionale in PEP-0448 . Inoltre, questa non è una funzione python3.x, è una funzione python3.5 + :-).
mgilson,

@mgilson, questo spiegherebbe perché non è stato menzionato prima.
leewz,

6

Oltre alle chiamate di funzione, * args e ** kwargs sono utili nelle gerarchie di classi ed evitano anche di dover scrivere il __init__metodo in Python. Un utilizzo simile può essere visto in framework come il codice Django.

Per esempio,

def __init__(self, *args, **kwargs):
    for attribute_name, value in zip(self._expected_attributes, args):
        setattr(self, attribute_name, value)
        if kwargs.has_key(attribute_name):
            kwargs.pop(attribute_name)

    for attribute_name in kwargs.viewkeys():
        setattr(self, attribute_name, kwargs[attribute_name])

Una sottoclasse può quindi essere

class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

La sottoclasse viene quindi istanziata come

food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())

Inoltre, una sottoclasse con un nuovo attributo che ha senso solo per quell'istanza della sottoclasse può chiamare la classe Base __init__per scaricare l'impostazione degli attributi. Questo viene fatto attraverso * args e ** kwargs. kwargs principalmente usato in modo che il codice sia leggibile usando argomenti denominati. Per esempio,

class ElectronicAccessories(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['specifications']
    # Depend on args and kwargs to populate the data as needed.
    def __init__(self, specifications = None, *args, **kwargs):
        self.specifications = specifications  # Rest of attributes will make sense to parent class.
        super(ElectronicAccessories, self).__init__(*args, **kwargs)

che può essere installato come

usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')

Il codice completo è qui


1
1. Fondamentalmente init è un metodo, quindi (in questo contesto) non è molto diverso. 2. Usa # per i commenti, non "" ", che segna solo stringhe letterali. 3. L'uso di super dovrebbe essere il modo preferito, specialmente per il tuo esempio con eredità multi-livello.
0xc0de

4

Sulla base della risposta di Nickd ...

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


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


def three_params(param1, *param2, **param3):
    print(param1)
    print(param2)
    print(param3)


foo(1, 2, 3, 4, 5)
print("\n")
bar(1, a=2, b=3)
print("\n")
three_params(1, 2, 3, 4, s=5)

Produzione:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

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

Fondamentalmente, qualsiasi numero di argomenti posizionali può usare * args e qualsiasi argomento denominato (o kwargs aka argomenti di parole chiave) può usare ** kwargs.


3

*argse **kwargs: consente di passare un numero variabile di argomenti a una funzione.

*args: viene utilizzato per inviare un elenco di argomenti di lunghezza variabile senza parole chiave alla funzione:

def args(normal_arg, *argv):
    print("normal argument:", normal_arg)

    for arg in argv:
        print("Argument in list of arguments from *argv:", arg)

args('animals', 'fish', 'duck', 'bird')

Produrrà:

normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird

**kwargs*

**kwargsconsente di passare una lunghezza variabile di parole chiave di argomenti a una funzione. È necessario utilizzare **kwargsse si desidera gestire argomenti con nome in una funzione.

def who(**kwargs):
    if kwargs is not None:
        for key, value in kwargs.items():
            print("Your %s is %s." % (key, value))

who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")  

Produrrà:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.

2

Questo esempio ti aiuterebbe a ricordare *args, **kwargse persino supered eredità in Python in una sola volta.

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg

class child2(base):
    def __init__(self, child_param, **kwargs):
        self.child_param = child_param
        super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg

c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1

1

Un buon esempio di utilizzo di entrambi in una funzione è:

>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}

1

TL; DR

Di seguito sono riportati 6 diversi casi d'uso per *e **nella programmazione di Python:

  1. Per accettare un numero qualsiasi di argomenti posizionali usando *args: def foo(*args): pass , qui fooaccetta qualunque numero di argomenti posizionali, vale a dire, le seguenti chiamate sono validi foo(1),foo(1, 'bar')
  2. Per accettare un numero qualsiasi di argomenti a parola chiave usando **kwargs: def foo(**kwargs): pass , qui 'pippo' accetta qualunque numero di argomenti a parola chiave, vale a dire, le seguenti chiamate sono validi foo(name='Tom'),foo(name='Tom', age=33)
  3. Per accettare un numero qualsiasi di argomenti posizionali e parole chiave utilizzando *args, **kwargs: def foo(*args, **kwargs): pass , qui fooaccetta qualunque numero di argomenti posizionali e parole chiave, vale a dire, le seguenti chiamate sono validi foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Per applicare parola chiave solo argomenti utilizzando *: def foo(pos1, pos2, *, kwarg1): pass , qui *significa che foo accettano solo argomenti chiave dopo pos2, quindi foo(1, 2, 3)solleva TypeError ma foo(1, 2, kwarg1=3)è ok.
  5. Non esprimere ulteriore interesse per altri argomenti posizionali usando *_(Nota: questa è solo una convenzione): def foo(bar, baz, *_): pass significa (per convenzione) foousa solo bare bazargomenti nel suo funzionamento e ignorerà gli altri.
  6. Non esprimere ulteriore interesse per più argomenti di parole chiave usando \**_(Nota: questa è solo una convenzione): def foo(bar, baz, **_): pass significa (per convenzione) foousa solo bare bazargomenti nel suo funzionamento e ignorerà gli altri.

BONUS: da Python 3.8 in poi, è possibile utilizzare /nella definizione della funzione per applicare parametri solo posizionali. Nell'esempio seguente, i parametri aeb sono solo posizionali , mentre c o d possono essere posizionali o parole chiave, e e o f devono essere parole chiave:

def f(a, b, /, c, d, *, e, f):
    pass

0

TL; DR

Comprime gli argomenti passati alla funzione all'interno liste dictrispettivamente all'interno del corpo della funzione. Quando si definisce una firma di funzione come questa:

def func(*args, **kwds):
    # do stuff

può essere chiamato con qualsiasi numero di argomenti e argomenti di parole chiave. Gli argomenti non di parole chiave vengono impacchettati in un elenco chiamato argsall'interno del corpo della funzione e gli argomenti di parole chiave vengono impacchettati in un dict chiamato kwdsall'interno del corpo della funzione.

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

ora all'interno del corpo della funzione, quando viene chiamata la funzione, ci sono due variabili locali, argsche è un elenco con valore ["this", "is a list of", "non-keyword", "arguments"]e kwdsche ha un dictvalore{"keyword" : "ligma", "options" : [1,2,3]}


Questo funziona anche al contrario, cioè dal lato del chiamante. ad esempio se hai una funzione definita come:

def f(a, b, c, d=1, e=10):
    # do stuff

puoi chiamarlo scompattando iterables o mapping che hai nell'ambito di chiamata:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)

0

Contesto

  • python 3.x
  • disimballaggio con **
  • utilizzare con la formattazione di stringhe

Utilizzare con la formattazione di stringhe

Oltre alle risposte in questo thread, ecco un altro dettaglio che non è stato menzionato altrove. Questo si espande sulla risposta di Brad Solomon

Il disimballaggio con **è utile anche quando si usa Python str.format.

Questo è in qualche modo simile a quello che puoi fare con la f-strings f-string di Python ma con l'overhead aggiunto di dichiarare un dict per contenere le variabili (f-string non richiede un dict).

Esempio rapido

  ## init vars
  ddvars = dict()
  ddcalc = dict()
  pass
  ddvars['fname']     = 'Huomer'
  ddvars['lname']     = 'Huimpson'
  ddvars['motto']     = 'I love donuts!'
  ddvars['age']       = 33
  pass
  ddcalc['ydiff']     = 5
  ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
  pass
  vdemo = []

  ## ********************
  ## single unpack supported in py 2.7
  vdemo.append('''
  Hello {fname} {lname}!

  Today you are {age} years old!

  We love your motto "{motto}" and we agree with you!
  '''.format(**ddvars)) 
  pass

  ## ********************
  ## multiple unpack supported in py 3.x
  vdemo.append('''
  Hello {fname} {lname}!

  In {ydiff} years you will be {ycalc} years old!
  '''.format(**ddvars,**ddcalc)) 
  pass

  ## ********************
  print(vdemo[-1])

-2
  • def foo(param1, *param2):è un metodo che può accettare un numero arbitrario di valori per *param2,
  • def bar(param1, **param2): è un metodo che può accettare un numero arbitrario di valori con chiavi per *param2
  • param1 è un parametro semplice.

Ad esempio, la sintassi per l'implementazione di varargs in Java come segue:

accessModifier methodName(datatype arg) {
    // method body
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.