2015-11-05 16 views
7

Se non so quanti argomenti sarà passata una funzione, ho potuto scrivere la funzione usando imballaggio argomento:Perché usare * args/** kwargs compressi invece di passare lista/dict?

def add(factor, *nums): 
    """Add numbers and multiply by factor.""" 
    return sum(nums) * factor 

In alternativa, ho potuto evitare di imballaggio argomento passando un elenco di numeri come il argomento:

def add(factor, nums): 
    """Add numbers and multiply by factor. 

    :type factor: int 
    :type nums: list of int 
    """ 
    return sum(nums) * factor 

esiste un vantaggio di utilizzare argomento imballaggio *args sopra il superamento di un elenco di numeri? O ci sono situazioni in cui uno è più appropriato?

+2

In modo che non sia * necessario * passare in una struttura in primo luogo. –

+1

Osservare la sintassi di chiamata.Scegli quello che preferisci per il compito. –

+0

@ IgnacioVazquez-Abrams Qual è il vantaggio? È altrettanto facile mettere le parentesi attorno agli argomenti. – DBedrenko

risposta

5

*args/**kwargs ha i suoi vantaggi, in genere nei casi in cui si desidera essere in grado di passare in una struttura dati decompressa, pur mantenendo la possibilità di lavorare con quelli imballati. Python 3 print() è un buon esempio.

print('hi') 
print('you have', num, 'potatoes') 
print(*mylist) 

Contrasto che con quello che sarebbe come se print() ha preso solo una struttura al sacco e poi ampliato all'interno della funzione:

print(('hi',)) 
print(('you have', num, 'potatoes')) 
print(mylist) 

In questo caso, *args/**kwargs viene in realtà a portata di mano.

Naturalmente, se ci si aspetta la funzione da sempre passato più argomenti contenuti in una struttura di dati, come sum() e str.join() fare, potrebbe avere più senso per lasciare fuori la sintassi *.

1

Riguarda l'API: * args fornisce un'interfaccia migliore, in quanto afferma che il metodo accetta un numero arbitrario di argomenti E questo è tutto, senza ulteriori presupposti. Sai per certo che il metodo stesso non farà altro con la struttura dati contenente i vari argomenti E che non è necessaria alcuna struttura dati speciale.

In teoria, è possibile anche accettare un dizionario con valori impostati su Nessuno. Perchè no? È sovraccarico e inutile. Per me, accettare un elenco quando è possibile accettare vararg è un sovraccarico. (come indicato da uno dei commenti)

Inoltre, i vararg sono un buon modo per garantire la coerenza e un buon contratto tra il chiamante e la funzione chiamata. Nessuna ipotesi può essere fatta.

Quando e se avete bisogno di una lista, allora sapete che avete bisogno di una lista!

Ah, notare che f (* args) non è lo stesso di f (elenco): il secondo desidera un elenco, il primo accetta un numero arbitrario di parametri (0 incluso). Ok, quindi cerchiamo di definire il secondo come argomento opzionale:

def f(l = []): pass 

fredda, ora avete due problemi, perché è necessario assicurarsi che non modificare l'argomento l: default parameter values. Per quale ragione? Perché non ti piacciono * args. :)

PS: Penso che questo sia uno dei maggiori svantaggi dei linguaggi dinamici: non si vede più l'interfaccia, ma sì! c'è un'interfaccia!

+0

Quest'ultimo esempio è un po 'forzato, in quanto è in genere risolto con 'def f (l = None): l = l o [] '... – deceze

+0

Perché dovresti farlo, quando puoi usare * arg? Questo è il punto. Sto offrendo una firma di funzione cattiva e devo anche risolverlo? Questo è il codice boilerplate per risolvere un problema di progettazione. – Markon

+0

Penso che questi problemi non siano correlati. Se vuoi offrire una firma di funzione variadica, '* args' è il modo più semplice per farlo. Se vuoi offrire una firma a argomento singolo come lista, 'None' è il modo per farlo. Non si aggiusta una funzione con la firma 'f (l: list = None)' usando una firma completamente diversa 'f (* args)'. Quello che vuoi che la tua API appaia come prima cosa, come implementarlo al meglio. – deceze