star - splat operator python




Che cosa fanno**(stella doppia/asterisco) e*(asterisco/asterisco) per i parametri? (12)

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

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

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

Consentono di definire le funzioni da accettare e per consentire agli utenti di passare qualsiasi numero di argomenti, posizionale ( * ) e parola chiave ( ** ).

Definizione di funzioni

*args consente qualsiasi numero di argomenti posizionali opzionali (parametri), che saranno assegnati ad una tupla chiamata args .

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

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

Espansione, passando un numero qualsiasi di argomenti

Puoi anche usare *args e **kwargs per passare in parametri da liste (o qualsiasi iterable) e dicts (o qualsiasi mapping), rispettivamente.

La funzione che riceve i parametri non deve sapere che sono stati espansi.

Ad esempio, xrange di Python 2 non prevede esplicitamente *args , ma dal momento che prende 3 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à in Python 3: definizione delle funzioni con argomenti solo parole chiave

Puoi avere argomenti con parole chiave solo dopo il *args - per esempio, qui, kwarg2 deve essere dato come argomento della parola chiave - non in modo posizionale:

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 usato da solo per indicare che seguono solo argomenti con parole chiave, senza consentire argomenti posizionali illimitati.

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

Qui, ancora una volta kwarg2 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 richiediamo che kwarg sia dato per nome, non in posizione:

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

In questo esempio, vediamo che se proviamo a passare kwarg posizione, 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 parametro kwarg come argomento della parola chiave.

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

Demo compatibili con Python 2

*args (tipicamente detto "star-args") e **kwargs (le stelle possono essere implicite dicendo "kwargs", ma essere esplicite con "double-star kwargs") sono idiomi comuni di Python per usare la notazione * e ** . Questi specifici nomi di variabili non sono richiesti (ad esempio potresti usare *foos e **bars ), ma un allontanamento dalla convenzione rischia di far arrabbiare i tuoi colleghi coder Python.

Generalmente li usiamo quando non sappiamo quale sarà la nostra funzione o quanti argomenti possiamo passare, e talvolta anche nominando ogni variabile separatamente risulterebbe molto disordinata e ridondante (ma questo è un caso in cui solitamente è esplicito meglio di implicito).

Esempio 1

La seguente funzione descrive come possono essere utilizzati e dimostra il comportamento. Si noti che l'argomento b nome verrà utilizzato dal secondo argomento posizionale prima:

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 l'aiuto online per la firma della funzione, con l' 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) stampa:

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, 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 per scopi illustrativi.

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, e quindi il nostro esempio qui sotto dimostra come *args e **kwargs possono essere molto utili:

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, come abbiamo calcolato 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, calcolando il nostro codice, che *args e **kwargs ci consente di fare, riduciamo le linee di codice, miglioriamo la leggibilità e la manutenibilità, e abbiamo solo posizioni canoniche per la logica del nostro programma. Se abbiamo bisogno di cambiare qualsiasi parte di questa struttura, abbiamo un posto in cui fare ogni cambiamento.


Per quelli di voi che imparano dagli esempi!

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

Cerchiamo di mostrarlo definendo una funzione che prende due variabili normali x , y , e può accettare più argomenti come myArgs , e può accettare ancora più argomenti come myKW . Più tardi, mostreremo come nutrire y usando 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 di argomenti non opzionali avviene prima.
  3. Non è possibile utilizzare due volte un argomento non facoltativo.
  4. Se applicabile, ** deve venire dopo * , sempre.

Cerchiamo prima di capire quali sono gli argomenti posizionali e gli argomenti delle parole chiave. Di seguito è riportato un esempio di definizione di 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 parola chiave / nome:

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.

Facciamo 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 una lista 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 '*' impacchetta gli argomenti ricevuti in una tupla.

Ora vediamo 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 '**' impacchetta gli argomenti ricevuti in un dizionario.

Quindi ricorda:

In una chiamata di funzione il '*' decomprime la struttura dei dati di tupla o lista in argomenti posizionali o parola chiave che devono essere ricevuti dalla definizione della funzione.

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

In una definizione di funzione il '*' raggruppa gli argomenti posizionali in una tupla.

In una definizione di funzione il '**' impacchetta gli argomenti delle parole chiave in un dizionario.


Dalla documentazione di Python:

Se ci sono più argomenti posizionali di quanti sono 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 ci sono argomenti posizionali in eccesso).

Se un argomento parola chiave non corrisponde a un nome di 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 di parole chiave in eccesso (utilizzando le parole chiave come chiavi e i valori dell'argomento come valori corrispondenti) o un (nuovo) dizionario vuoto se non ci sono argomenti di parole chiave in eccesso.


Il singolo * significa che può esserci un numero qualsiasi di argomenti posizionali extra. foo() può essere invocato come foo(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 con nome extra. 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'output è

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

In Python 3.5, è anche possibile utilizzare questa sintassi in list , dict , tuple e set display (anche a volte chiamati letterali). Vedi PEP 488: generalizzazioni di disimballaggio aggiuntive .

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

Consente inoltre di decomprimere più iterables in una singola chiamata di funzione.

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

(Grazie a mgilson per il collegamento PEP.)


Oltre alle chiamate alle funzioni, * args e ** kwargs sono utili nelle gerarchie di classi ed evitano anche di dover scrivere il metodo __init__ 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 sarà 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 abbia senso solo per quell'istanza di sottoclasse può chiamare la classe Base __init__ per scaricare l'impostazione degli attributi. Questo viene fatto tramite * args e ** kwargs. kwargs principalmente usato in modo che il codice sia leggibile usando argomenti con nome. 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 istatato 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 è here


Questo esempio ti aiuterà a ricordare *args , **kwargs e persino super ed ereditarietà in Python in una 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

Vale anche la pena notare che è possibile usare * e ** quando si chiamano le funzioni. Questa è una scorciatoia che consente di passare più argomenti a una funzione direttamente usando una lista / tupla o un dizionario. Ad esempio, se hai la 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: le chiavi in mydict devono essere denominate esattamente come i parametri della funzione foo . Altrimenti verrà TypeError 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'

Voglio dare 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]

Lo zip () riceve più argomenti irable e restituisce un generatore.

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

* significa ricevere argomenti variabili come lista

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

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

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

Produzione:

dic1 two
dic2 3

*args e **kwargs : consentono di passare un numero variabile di argomenti a una funzione.

*args : è usato per inviare alla funzione una lista di argomenti di lunghezza variabile senza parole chiave:

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*

**kwargs consente di passare una lunghezza variabile di argomenti con parole chiave a una funzione. Dovresti usare **kwargs se vuoi gestire gli 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.




kwargs