È possibile passare un numero variabile di argomenti a una funzione?


345

In modo simile all'utilizzo di varargs in C o C ++:

fn(a, b)
fn(a, b, c, d, ...)

5
Riferisco l'onorevole lotta al podcast 53: itc.conversationsnetwork.org/shows/…
David Sykes,

2
Devo andare con il signor Lott su questo. Puoi ottenere rapidamente una risposta autorevole su questo nei documenti di Python, inoltre avrai un'idea di cos'altro c'è nei documenti. È a tuo vantaggio conoscere questi documenti se prevedi di lavorare in Python.
Brian Neal,

@DavidSykes Il collegamento è interrotto
Dave Liu il

Risposte:


447

Sì. È possibile utilizzare *argscome argomento non di parole chiave . Sarai quindi in grado di passare qualsiasi numero di argomenti.

def manyArgs(*arg):
  print "I was called with", len(arg), "arguments:", arg

>>> manyArgs(1)
I was called with 1 arguments: (1,)
>>> manyArgs(1, 2, 3)
I was called with 3 arguments: (1, 2, 3)

Come puoi vedere, Python decomprimerà gli argomenti come una singola tupla con tutti gli argomenti.

Per gli argomenti delle parole chiave è necessario accettarli come argomenti effettivi separati, come mostrato nella risposta di Skurmedel .


8
Anche importante ... si potrebbe trovare un momento in cui devono passare un numero sconosciuto di argomenti a una funzione. In un caso come questo, chiama il tuo "manyArgs" creando un elenco chiamato "args" e passandolo a manyArgs in questo modo "manyArgs (* args)"
wilbbe01

4
Questo è vicino, ma purtroppo non è abbastanza generale: manyArgs(x = 3)fallisce TypeError. La risposta di Skumedel mostra la soluzione a questo. Il punto chiave è che la firma generale di una funzione è f(*list_args, **keyword_args)(non f(*list_args)).
Eric O Lebigot,

2
Il tipo di argsè tuple. kwargssignifica parole chiave args . Il tipo di kwargsè dictionary.
RoboAlex

1
Solo for arg in args:per iterare attraverso args passati
MasterControlProgram

228

Aggiunta al messaggio di svolgimento:

Puoi anche inviare più argomenti chiave-valore.

def myfunc(**kwargs):
    # kwargs is a dictionary.
    for k,v in kwargs.iteritems():
         print "%s = %s" % (k, v)

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

E puoi mescolare i due:

def myfunc2(*args, **kwargs):
   for a in args:
       print a
   for k,v in kwargs.iteritems():
       print "%s = %s" % (k, v)

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

Devono essere entrambi dichiarati e chiamati in quell'ordine, ovvero la funzione firma deve essere * args, ** kwargs e chiamata in quell'ordine.


2
Non sono sicuro di come funzioni myfunc (abc = 123, def = 456), ma nel mio (2.7), 'def' non può essere passato in questa funzione senza ottenere SyntaxError. Suppongo che ciò sia dovuto al fatto che def ha significato in Python. Prova invece myfunc (abc = 123, fgh = 567). (Altrimenti, ottima risposta e grazie per questo!)
Dannid,

@Dannid: Nessuna idea, ahah ... non funziona neanche su 2.6 o 3.2. Lo rinominerò.
Skurmedel,

Quando dici "chiamato in quell'ordine", vuoi dire passato in quell'ordine? O qualcos'altro?
Nikhil Prabhu,

1
@NikhilPrabhu: Sì. Gli argomenti delle parole chiave devono arrivare per ultimi quando lo chiami. Vengono sempre per ultimi se nella chiamata sono presenti anche argomenti non relativi a parole chiave.
Skurmedel,

2
Per Python 3: basta scambiare print acon print(a)e kwargs.iteritems():con kwargs.items().
MasterControlProgram

22

Se posso, il codice di Skurmedel è per Python 2; per adattarlo a Python 3, passare iteritemsa itemse aggiungere parentesi a print. Ciò potrebbe impedire ai principianti come me di imbattersi in: AttributeError: 'dict' object has no attribute 'iteritems'e cercare altrove (ad esempio, l' errore "oggetto" dict "non ha alcun attributo" iteritems "" quando si cerca di utilizzare write_shp () di NetworkX perché questo accada.

def myfunc(**kwargs):
for k,v in kwargs.items():
   print("%s = %s" % (k, v))

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

e:

def myfunc2(*args, **kwargs):
   for a in args:
       print(a)
   for k,v in kwargs.items():
       print("%s = %s" % (k, v))

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

12

Aggiungendo agli altri post eccellenti.

A volte non vuoi specificare il numero di argomenti e vuoi usare le chiavi per loro (il compilatore si lamenterà se un metodo passato in un dizionario non è usato nel metodo).

def manyArgs1(args):
  print args.a, args.b #note args.c is not used here

def manyArgs2(args):
  print args.c #note args.b and .c are not used here

class Args: pass

args = Args()
args.a = 1
args.b = 2
args.c = 3

manyArgs1(args) #outputs 1 2
manyArgs2(args) #outputs 3

Quindi puoi fare cose come

myfuns = [manyArgs1, manyArgs2]
for fun in myfuns:
  fun(args)

2
def f(dic):
    if 'a' in dic:
        print dic['a'],
        pass
    else: print 'None',

    if 'b' in dic:
        print dic['b'],
        pass
    else: print 'None',

    if 'c' in dic:
        print dic['c'],
        pass
    else: print 'None',
    print
    pass
f({})
f({'a':20,
   'c':30})
f({'a':20,
   'c':30,
   'b':'red'})
____________

verrà emesso il codice sopra

None None None
20 None 30
20 red 30

Questo è buono come passare argomenti variabili per mezzo di un dizionario


3
Questo è un codice terribile. Molto meglio sarebbe:f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')
metaperture il

0

Un altro modo di procedere, oltre alle belle risposte già menzionate, dipende dal fatto che puoi passare argomenti nominativi opzionali per posizione. Per esempio,

def f(x,y=None):
    print(x)
    if y is not None:
        print(y)

I rendimenti

In [11]: f(1,2)
1
2

In [12]: f(1)
1
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.