2008-11-13 19 views
231

Che cosa significano esattamente *args e **kwargs?Cosa significano * args e ** kwargs?

Secondo la documentazione Python, da quello che sembra, passa in una tupla di argomenti.

def foo(hello, *args): 
    print hello 

    for each in args: 
     print each 

if __name__ == '__main__': 
    foo("LOVE", ["lol", "lololol"]) 

Questo stampa:

LOVE 
['lol', 'lololol'] 

Come si fa a utilizzare in modo efficace?

+13

Solo un cattivo gioco di parole su Ore e Kilo - Ore di lavoro. – Mostlyharmless

+6

Questo articolo può essere molto utile per comprendere a fondo il tema: http://agiliq.com/blog/2012/06/understanding-args-and-kwargs/ –

risposta

225

Inserire *args e/o **kwargs come ultimo elemento nell'elenco di argomenti della definizione della funzione consente a tale funzione di accettare un numero arbitrario di argomenti e/o argomenti di parole chiave.

Ad esempio, se si voleva scrivere una funzione che ha restituito la somma di tutti i suoi argomenti, non importa quanti si fornisce, si potrebbe scrivere in questo modo:

def my_sum(*args): 
    return sum(args) 

è probabilmente più comunemente usato in programmazione orientata agli oggetti, quando si sta sovrascrivendo una funzione, e si vuole chiamare la funzione originale con qualsiasi argomento l'utente passa.

in realtà non è necessario chiamarli args e kwargs, questo è solo una convenzione. È lo * e lo ** a fare la magia.

La documentazione ufficiale di Python ha a more in-depth look.

+5

Nessun problema, siete i benvenuti. Mi sono confuso per un po '. Se stai entrando seriamente in Python, raccomando vivamente "Programming Python" di Mark Lutz. –

+39

Forse il link al tutorial che spiega questo in profondità, e dovrebbe essere letto da tutti: http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions –

+1

@AliAfshar: il tuo link era tutto Avevo bisogno, avrebbe dovuto essere la risposta da sola. Grazie! – scorpiodawg

82

Inoltre, li usiamo per gestire l'ereditarietà.

class Super(object): 
    def __init__(self, this, that): 
     self.this = this 
     self.that = that 

class Sub(Super): 
    def __init__(self, myStuff, *args, **kw): 
     super(Sub, self).__init__(*args, **kw) 
     self.myStuff= myStuff 

x= Super(2.7, 3.1) 
y= Sub("green", 7, 6) 

In questo modo Sub non sa (o cura) cosa sia l'inizializzazione della superclasse. Se ti rendi conto che devi cambiare la superclasse, puoi aggiustare le cose senza dover sudare i dettagli in ogni sottoclasse.

+6

Questa è una delle risposte più utili che ho trovato su come usare 'super'. Questa risposta ha più di 5 anni, ma immagino che questo sia ancora un ottimo modo per usare 'super' in Python 2.X, corretto? –

+0

Sì, ancora il modo di farlo. –

+0

Grazie, ma sarebbe bello se potessi fornire qualche esempio reale, perché e quando usarlo. Nell'esempio sopra cosa succede se non lo faccio? – TaraGurung

63

Avviso la cosa più cool in S.Lott's comment - si può anche richiamare le funzioni con *mylist e **mydict di disfare argomenti posizionali e parole chiave:

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

l = [0, 1] 
d = {"d":3, "c":2} 

foo(*l, **d) 

stamperà: 0 1 2 3

+0

Si può effettivamente fare anche '* mydict' (non' ** mylist'), ma il risultato sarà leggermente diverso (e inaspettato per alcuni). – Tadeck

+1

semplice, conciso, e un esempio facile da seguire per illustrare il punto. Il mio tipo preferito di risposta! – NickO

+0

@Tadeck È possibile eseguire '* x' per qualsiasi iterabile e' ** y' per qualsiasi tipo di mapping. Dal momento che un ditt è sia un iterable sia una mappatura puoi farlo entrambi. Vedi anche http://stackoverflow.com/questions/8601268/python-class-that-acts-as-mapping-for-unpacking – augurar

24

Un altro buon uso per *args e **kwargs: è possibile definire generiche funzioni "catch all", il che è ottimo per i decoratori in cui si restituisce tale wrapper anziché la funzione originale.

Un esempio con una banale caching decoratore:

import pickle, functools 
def cache(f): 
    _cache = {} 
    def wrapper(*args, **kwargs): 
    key = pickle.dumps((args, kwargs)) 
    if key not in _cache: 
     _cache[key] = f(*args, **kwargs) # call the wrapped function, save in cache 
    return _cache[key] # read value from cache 
    functools.update_wrapper(wrapper, f) # update wrapper's metadata 
    return wrapper 

import time 
@cache 
def foo(n): 
    time.sleep(2) 
    return n*2 

foo(10) # first call with parameter 10, sleeps 
foo(10) # returns immediately 
15

solo per chiarire come disimballare gli argomenti, e prendersi cura di argomenti mancanti ecc

def func(**keyword_args): 
    #-->keyword_args is a dictionary 
    print 'func:' 
    print keyword_args 
    if keyword_args.has_key('b'): print keyword_args['b'] 
    if keyword_args.has_key('c'): print keyword_args['c'] 

def func2(*positional_args): 
    #-->positional_args is a tuple 
    print 'func2:' 
    print positional_args 
    if len(positional_args) > 1: 
    print positional_args[1] 

def func3(*positional_args, **keyword_args): 
    #It is an error to switch the order ie. def func3(**keyword_args, *positional_args): 
    print 'func3:' 
    print positional_args 
    print keyword_args 

func(a='apple',b='banana') 
func(c='candle') 
func2('apple','banana')#It is an error to do func2(a='apple',b='banana') 
func3('apple','banana',a='apple',b='banana') 
func3('apple',b='banana')#It is an error to do func3(b='banana','apple') 
Problemi correlati