¿Se puede pasar un número variable de argumentos a una función?

345

De manera similar al uso de varargs en C o C ++:

fn(a, b)
fn(a, b, c, d, ...)
David Sykes
fuente
55
Remito la honorable lotería al podcast 53: itc.conversationsnetwork.org/shows/…
David Sykes
2
Tengo que ir con el señor Lott en este caso. Puede obtener rápidamente una respuesta de autoría en este caso en los documentos de Python, además tendrá una idea de qué más hay en los documentos. Le conviene conocer esos documentos si planea trabajar en Python.
Brian Neal
@DavidSykes Link está roto
Dave Liu

Respuestas:

447

Si. Puede usarlo *argscomo argumento sin palabras clave . Entonces podrá pasar cualquier número de argumentos.

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)

Como puede ver, Python descomprimirá los argumentos como una tupla única con todos los argumentos.

Para los argumentos de palabras clave, debe aceptarlos como un argumento real separado, como se muestra en la respuesta de Skurmedel .

relajarse
fuente
8
También es importante ... uno puede encontrar un momento en que tienen que pasar un número desconocido de argumentos a una función. En un caso como este, llame a sus "manyArgs" creando una lista llamada "args" y pasándola a manyArgs como este "manyArgs (* args)"
wilbbe01
44
Esto está cerca, pero desafortunadamente no es lo suficientemente general: manyArgs(x = 3)falla con TypeError. La respuesta de Skumedel muestra la solución a esto. El punto clave es que la firma general de una función es f(*list_args, **keyword_args)(no f(*list_args)).
Eric O Lebigot
2
El tipo de argses tuple. kwargssignifica palabra clave args . El tipo de kwargsesdictionary .
RoboAlex
1
Solo for arg in args:por iterar a través de argumentos pasados
MasterControlProgram
228

Agregando a desenrolla publicación:

También puede enviar múltiples argumentos clave-valor.

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

Y puedes mezclar los dos:

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

Deben declararse y llamarse en ese orden, es decir, la firma de la función debe ser * args, ** kwargs y llamarse en ese orden.

Skurmedel
fuente
2
No estoy seguro de cómo consiguió que myfunc (abc = 123, def = 456) funcionara, pero en el mío (2.7), 'def' no se puede pasar en esta función sin obtener un SyntaxError. Supongo que esto se debe a que def tiene significado en python. Pruebe myfunc (abc = 123, fgh = 567) en su lugar. (De lo contrario, ¡gran respuesta y gracias por eso!)
Dannid
@ Dannid: Ni idea jaja ... tampoco funciona en 2.6 o 3.2. Lo renombraré.
Skurmedel
Cuando dice 'llamado en ese orden', ¿quiere decir que pasó en ese orden? ¿O algo mas?
Nikhil Prabhu
1
@NikhilPrabhu: Sí. Los argumentos de palabras clave deben ser los últimos cuando lo llame. Siempre vienen al final si también tiene argumentos que no son palabras clave en la llamada.
Skurmedel
2
Para Python 3: simplemente intercambie print acon print(a)y kwargs.iteritems():con kwargs.items().
MasterControlProgram
22

Si puedo, el código de Skurmedel es para python 2; para adaptarla a Python 3, el cambio iteritemsde itemsy añadir paréntesis print. Eso podría evitar que los principiantes como yo se encuentren: AttributeError: 'dict' object has no attribute 'iteritems'y busquen en otro lugar (p. Ej., El error "objeto 'dict' no tiene el atributo 'iteritems'" al intentar usar write_shp () de NetworkX por qué sucede esto.

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

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

y:

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
calocedrus
fuente
12

Agregando a las otras publicaciones excelentes.

A veces no desea especificar el número de argumentos y desea utilizar claves para ellos (el compilador se quejará si un argumento pasado en un diccionario no se usa en el método).

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

Entonces puedes hacer cosas como

myfuns = [manyArgs1, manyArgs2]
for fun in myfuns:
  fun(args)
Vladtn
fuente
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'})
____________

saldrá el código anterior

None None None
20 None 30
20 red 30

Esto es tan bueno como pasar argumentos variables por medio de un diccionario

BN Venkataraman
fuente
3
Este es un código terrible. Mucho mejor sería:f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')
metaperture
0

Otra forma de hacerlo, además de las buenas respuestas ya mencionadas, depende del hecho de que puede pasar argumentos nombrados opcionales por posición. Por ejemplo,

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

Rendimientos

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

In [12]: f(1)
1
condición de transversalidad
fuente