number - python3 variable arguments




* args e** kwargs? (8)

* args e ** kwargs sono funzioni speciali magiche di Python. Pensa a una funzione che potrebbe avere un numero sconosciuto di argomenti. Ad esempio, per qualsiasi motivo, si desidera disporre di una funzione che sommi un numero sconosciuto di numeri (e non si desidera utilizzare la funzione somma incorporata). Quindi scrivi questa funzione:

def sumFunction(*args):
  result = 0
  for x in args:
    result += x
  return result

e usarlo come: sumFunction (3,4,6,3,6,8,9).

** kwargs ha una funzione diversa. Con ** kwargs puoi dare argomenti di parole chiave arbitrarie a una funzione e puoi accedervi come un dictonary.

def someFunction(**kwargs):
  if 'text' in kwargs:
    print kwargs['text']

Chiamando someFunction (text = "foo") verrà stampato foo.

Quindi ho difficoltà con il concetto di *args e **kwargs .

Finora ho imparato che:

  • *args = elenco di argomenti - come argomenti posizionali
  • **kwargs = dizionario - le cui chiavi diventano argomenti separati per le parole chiave e i valori diventano valori di questi argomenti.

Non capisco per quale compito di programmazione sarebbe utile.

Può essere:

Penso di inserire liste e dizionari come argomenti di una funzione E allo stesso tempo di un jolly, quindi posso passare QUALSIASI argomento?

C'è un semplice esempio per spiegare come vengono usati *args e **kwargs ?

Anche il tutorial che ho trovato usato solo il "*" e un nome di variabile.

Are *args e **kwargs solo segnaposti o usi esattamente *args e **kwargs nel codice?


Ecco un esempio che utilizza 3 diversi tipi di parametri.

def func(required_arg, *args, **kwargs):
    # required_arg is a positional-only parameter.
    print required_arg

    # args is a tuple of positional arguments,
    # because the parameter name has * prepended.
    if args: # If args is not empty.
        print args

    # kwargs is a dictionary of keyword arguments,
    # because the parameter name has ** prepended.
    if kwargs: # If kwargs is not empty.
        print kwargs

>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes at least 1 argument (0 given)

>>> func("required argument")
required argument

>>> func("required argument", 1, 2, '3')
required argument
(1, 2, '3')

>>> func("required argument", 1, 2, '3', keyword1=4, keyword2="foo")
required argument
(1, 2, '3')
{'keyword2': 'foo', 'keyword1': 4}

I nomi *args e **kwargs o **kw sono puramente per convenzione. Rende più facile leggere il codice degli altri

Un posto è utile quando si utilizza il modulo struct

struct.unpack() restituisce una tupla mentre struct.pack() usa un numero variabile di argomenti. Quando si manipolano i dati è conveniente essere in grado di passare una tupla a struck.pack() es.

tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)

senza questa abilità saresti costretto a scrivere

new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)

che significa anche che se il formato_str cambia e la dimensione della tupla cambia, dovrò tornare indietro e modificare quella linea veramente lunga


Immagina di avere una funzione ma non vuoi limitare il numero di parametri che richiede. Esempio:

>>> import operator
>>> def multiply(*args):
...  return reduce(operator.mul, args)

Quindi usi questa funzione come:

>>> multiply(1,2,3)
6

or

>>> numbers = [1,2,3]
>>> multiply(*numbers)
6

Questi parametri vengono in genere utilizzati per le funzioni proxy, pertanto il proxy può passare qualsiasi parametro di input alla funzione di destinazione.

def foo(bar=2, baz=5):
    print bar, baz

def proxy(x, *args, **kwargs): # reqire parameter x and accept any number of additional arguments
    print x
    foo(*args, **kwargs) # applies the "non-x" parameter to foo

proxy(23, 5, baz='foo') # calls foo with bar=5 and baz=foo
proxy(6)# calls foo with its default arguments
proxy(7, bar='asdas') # calls foo with bar='asdas' and leave baz default argument

Ma poiché questi parametri nascondono i nomi dei parametri effettivi, è meglio evitarli.


Si noti che * args / ** kwargs fa parte della sintassi della funzione-chiamata, e non proprio un operatore. Questo ha un particolare effetto collaterale in cui mi sono imbattuto, ovvero che non è possibile usare l'espansione * args con l'istruzione print, poiché la stampa non è una funzione.

Questo sembra ragionevole:

def myprint(*args):
    print *args

Purtroppo non viene compilato (errore di sintassi).

Questo compila:

def myprint(*args):
    print args

Ma stampa gli argomenti come una tupla, che non è ciò che vogliamo.

Questa è la soluzione su cui mi sono basato:

def myprint(*args):
    for arg in args:
        print arg,
    print

Un posto in cui l'uso di *args e **kwargs è abbastanza utile è per la sottoclasse.

class Foo(object):
    def __init__(self, value1, value2):
        # do something with the values
        print value1, value2

class MyFoo(Foo):
    def __init__(self, *args, **kwargs):
        # do something else, don't care about the args
        print 'myfoo'
        super(MyFoo, self).__init__(*args, **kwargs)

In questo modo puoi estendere il comportamento della classe Foo, senza dover sapere troppo su Foo. Questo può essere abbastanza comodo se si sta programmando su un'API che potrebbe cambiare. MyFoo passa solo tutti gli argomenti alla classe Foo.


La sintassi è * e ** . I nomi *args e **kwargs sono solo per convenzione ma non è necessario utilizzarli.

Dovresti usare *args quando non sei sicuro di quanti argomenti potrebbero essere passati alla tua funzione, cioè ti permette di passare un numero arbitrario di argomenti alla tua funzione. Per esempio:

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print( '{0}. {1}'.format(count, thing))
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

Allo stesso modo, **kwargs ti consente di gestire argomenti con nome che non hai definito in anticipo:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print( '{0} = {1}'.format(name, value))
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

Puoi usarli anche insieme agli argomenti con nome. Gli argomenti espliciti ottengono i valori per primi e poi tutto il resto viene passato a *args e **kwargs . Gli argomenti nominati vengono prima nell'elenco. Per esempio:

def table_things(titlestring, **kwargs)

Puoi anche utilizzare entrambi nella stessa definizione di funzione, ma *args deve essere **kwargs prima di **kwargs .

È inoltre possibile utilizzare la sintassi * e ** quando si chiama una funzione. Per esempio:

>>> def print_three_things(a, b, c):
...     print( 'a = {0}, b = {1}, c = {2}'.format(a,b,c))
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat

Come puoi vedere in questo caso prende la lista (o tupla) di elementi e la decomprime. Da questo li abbina agli argomenti nella funzione. Naturalmente, si potrebbe avere un * sia nella definizione della funzione che nella chiamata di funzione.





kwargs