93 votes

Arguments par défaut avec *args et **kwargs

Sur Python 2.x (j'utilise 2.7), ce qui est la bonne façon d'utiliser les arguments par défaut avec *args y **kwargs ?
J'ai trouvé une question sur SO en rapport avec ce sujet, mais elle est pour Python 3 :
Appel d'une fonction Python avec *args, **kwargs et arguments optionnels / par défaut

Là-bas, ils disent que cette méthode fonctionne :

def func(arg1, arg2, *args, opt_arg='def_val', **kwargs):
    #...

En 2.7, cela se traduit par un SyntaxError . Existe-t-il une méthode recommandée pour définir une telle fonction ?
J'ai réussi à le faire fonctionner de cette façon, mais je suppose qu'il existe une solution plus agréable.

def func(arg1, arg2, *args, **kwargs):
    opt_arg ='def_val'
    if kwargs.__contains__('opt_arg'):
        opt_arg = kwargs['opt_arg']
    #...

103voto

nneonneo Points 56821

Il suffit de placer les arguments par défaut avant le *args :

def foo(a, b=3, *args, **kwargs):

Maintenant, b sera explicitement défini si vous le passez comme argument de mot-clé ou comme deuxième argument positionnel.

Exemples :

foo(x) # a=x, b=3, args=(), kwargs={}
foo(x, y) # a=x, b=y, args=(), kwargs={}
foo(x, b=y) # a=x, b=y, args=(), kwargs={}
foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={}
foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k}
foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}

Notez que, en particulier, foo(x, y, b=z) ne fonctionne pas car b est attribué par position dans ce cas.


Ce code fonctionne également en Python 3. Placer l'argument par défaut après *args dans Python 3 en fait un argument "mot-clé seulement" qui peut seulement être spécifié par son nom, et non par sa position. Si vous voulez un argument uniquement par mot-clé en Python 2, vous pouvez utiliser la méthode @mgilson solution .

61voto

mgilson Points 92954

La syntaxe utilisée dans l'autre question ne concerne que python3.x et ne spécifie que des arguments sous forme de mots-clés. Elle ne fonctionne pas sur python2.x.

Pour python2.x, je voudrais pop en dehors de kwargs :

def func(arg1, arg2, *args, **kwargs):
    opt_arg = kwargs.pop('opt_arg', 'def_val')

11voto

Roman Points 1983

Approche similaire à celle de @yaccob, mais claire et concise :

Sur Python 3.5 ou plus :

def foo(a, b=3, *args, **kwargs):
  defaultKwargs = { 'c': 10, 'd': 12 }
  kwargs = { **defaultKwargs, **kwargs }
  print(a, b, args, kwargs)

  # Do something    

foo(1) # 1 3 () {'c': 10, 'd': 12}
foo(1, d=5) # 1 3 () {'c': 10, 'd': 5}
foo(1, 2, 4, d=5) # 1 2 (4,) {'c': 10, 'd': 5}

Note : vous pouvez utiliser Dans Python 2

kwargs = merge_two_dicts(defaultKwargs, kwargs)

Sur Python 3.5

kwargs = { **defaultKwargs, **kwargs }

Sur Python 3.9

kwargs = defaultKwargs | kwargs  # NOTE: 3.9+ ONLY

5voto

Daniel Américo Points 51

Vous pouvez également utiliser un décorateur comme celui-ci :

import functools
def default_kwargs(**defaultKwargs):
    def actual_decorator(fn):
        @functools.wraps(fn)
        def g(*args, **kwargs):
            defaultKwargs.update(kwargs)
            return fn(*args, **defaultKwargs)
        return g
    return actual_decorator

Alors, faites-le :

@default_kwargs(defaultVar1 = defaultValue 1, ...)
def foo(*args, **kwargs):
    # Anything in here

Par exemple :

@default_kwargs(a=1)
def f(*args, **kwargs):
    print(kwargs['a']+ 1)

f() # Returns 2
f(3) # Returns 4

1voto

yaccob Points 688

En restant assez proche de votre approche de la solution tout en essayant de la rendre plus générique et plus compacte, je suggérerais d'envisager quelque chose comme ceci :

>>> def func(arg1, arg2, *args, **kwargs):
...     kwargs_with_defaults = dict({'opt_arg': 'def_val', 'opt_arg2': 'default2'}, **kwargs)
...     #...
...     return arg1, arg2, args, kwargs_with_defaults

>>> func('a1', 'a2', 'a3', 'a5', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'def_val', 'y': 'bar', 'x': 'foo'})

>>> func('a1', 'a2', 'a3', 'a5', opt_arg='explicit_value', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'explicit_value', 'y': 'bar', 'x': 'foo'})

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X