Existe-t-il un moyen de transmettre des paramètres facultatifs à une fonction?

133

Existe-t-il un moyen en Python de passer des paramètres optionnels à une fonction lors de son appel et dans la définition de la fonction avoir du code basé sur "uniquement si le paramètre optionnel est passé"

user1795998
la source

Réponses:

115

La documentation Python 2, 7.6. Les définitions de fonction vous offrent plusieurs façons de détecter si un appelant a fourni un paramètre facultatif.

Tout d'abord, vous pouvez utiliser une syntaxe de paramètre formel spéciale *. Si la définition de fonction a un paramètre formel précédé d'un seul *, Python remplit ce paramètre avec tous les paramètres de position qui ne correspondent pas aux paramètres formels précédents (sous forme de tuple). Si la définition de fonction a un paramètre formel précédé de **, Python remplit ce paramètre avec tous les paramètres de mot-clé qui ne correspondent pas aux paramètres formels précédents (sous forme de dict). L'implémentation de la fonction peut vérifier le contenu de ces paramètres pour tout "paramètre facultatif" du type souhaité.

Par exemple, voici une fonction opt_funqui prend deux paramètres de position x1et x2, et recherche un autre paramètre de mot-clé nommé "facultatif".

>>> def opt_fun(x1, x2, *positional_parameters, **keyword_parameters):
...     if ('optional' in keyword_parameters):
...         print 'optional parameter found, it is ', keyword_parameters['optional']
...     else:
...         print 'no optional parameter, sorry'
... 
>>> opt_fun(1, 2)
no optional parameter, sorry
>>> opt_fun(1,2, optional="yes")
optional parameter found, it is  yes
>>> opt_fun(1,2, another="yes")
no optional parameter, sorry

Deuxièmement, vous pouvez fournir une valeur de paramètre par défaut d'une certaine valeur comme Nonecelle qu'un appelant n'utiliserait jamais. Si le paramètre a cette valeur par défaut, vous savez que l'appelant n'a pas spécifié le paramètre. Si le paramètre n'a pas une valeur par défaut, vous savez qu'il provient de l'appelant.

Jim DeLaHunt
la source
7
positional_parametersest un tuple et keyword_parametersun dictionnaire.
Cees Timmerman
Comment python distingue-t-il formal parameters preceded by * (comment s'appelle-t-il?) D'un keyword parameter? Comme je l'ai compris, les paramètres de mot-clé sont spécifiés à l'aide de l' =opérateur dans l'appel de fonction ( opt_fun(1,2, optional="yes")fournit donc un argument de mot-clé "oui" pour une fonction qui anticipe, mais ne nécessite pas nécessairement, le paramètre option).
Minh Tran
D'un autre côté, j'ai compris formal parameters preceded by * simplement "les arguments fournis par l'appelant qui ne correspondent pas aux arguments positionnels qui précèdent les arguments de mot-clé". Par exemple, dans opt_fun(1,2, "blah", 3.14, mykey="yes", myyear="2018"), "blah"et 3.14sont forma arguments preceded by *parce qu'il est entre les deux arguments de position et l'argument qui utilise le =signe. Le tuple résultant positional_parameterserait le rythme binaire: ("blah", 3.14). Est-ce correct?
Minh Tran
@MinhTran, les questions dans les commentaires ne sont pas le meilleur moyen d'obtenir une réponse dans Stack Overflow. Il est de loin préférable de cliquer sur le gros bouton bleu «Poser une question» et d'écrire votre demande sous forme de «question» à laquelle les autres peuvent «répondre». Mais pour vous aider, a) notez que j'ai écrit " parameter" pas " parameters" pour " preceded by *". La langue n'en autorise qu'un *identifierdans la liste des paramètres. b) lire docs.python.org/2/reference/… , c) lire docs.python.org/2/reference/expressions.html#calls . Désolé, il n'y a plus de caractères autorisés dans ce commentaire.
Jim DeLaHunt
81
def my_func(mandatory_arg, optional_arg=100):
    print(mandatory_arg, optional_arg)

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values

Je trouve cela plus lisible que d'utiliser **kwargs.

Pour déterminer si un argument a été passé du tout, j'utilise un objet utilitaire personnalisé comme valeur par défaut:

MISSING = object()

def func(arg=MISSING):
    if arg is MISSING:
        ...
warvariuc
la source
-Merci, existe-t-il un moyen de spécifier la valeur par défaut de ce paramètre comme une autre variable dans le code?
user1795998
Oui. default_value=100; def my_func(mandatory_argument, optional_argument_with_default_value=default_value): ...
warvariuc
Cela semble montrer comment utiliser des paramètres optionnels, mais pas comment tester si l'un est réussi, ce que demande l'OP.
Mawg dit de réintégrer Monica
4
Dans la plupart des cas, c'est la solution la plus simple et la plus directe que celle de Jim. Si vous définissez la valeur par défaut sur Aucun, vous pouvez vérifier si le paramètre a été transmis ou non. Le seul cas où la solution de Jim est meilleure est s'il est important de faire la distinction entre passer None comme argument et ne pas passer d'argument du tout.
Arnon Axelrod
19
def op(a=4,b=6):
    add = a+b
    print add

i)op() [o/p: will be (4+6)=10]
ii)op(99) [o/p: will be (99+6)=105]
iii)op(1,1) [o/p: will be (1+1)=2]
Note:
 If none or one parameter is passed the default passed parameter will be considered for the function. 
Sanyal
la source
1
Existe-t-il un moyen de ne transmettre que le deuxième paramètre (b) et non le premier (a)?
Djidiouf
4
@Djidiouf Oui, il y aop(b=2)
Jürg Merlin Spaak
7

Si vous voulez donner une valeur par défaut à un paramètre, attribuez une valeur dans (). comme (x = 10). Mais il est important de commencer par l'argument obligatoire puis la valeur par défaut.

par exemple.

(y, x = 10)

mais

(x = 10, y) est faux

sumit
la source
Merci, existe-t-il un moyen de spécifier la valeur par défaut de ce paramètre comme une autre variable dans le code?
user1795998
Oui, vous pouvez utiliser quelque chose appelé *arg **kargcomme arguments de fonction. recherche sur Google.
sumit
Cela semble montrer comment utiliser des paramètres optionnels, mais pas comment tester si l'un est réussi, ce que demande l'OP.
Mawg dit de réintégrer Monica
2

Vous pouvez spécifier une valeur par défaut pour l'argument optionnel avec quelque chose qui ne serait jamais passé à la fonction et la vérifier avec l' isopérateur:

class _NO_DEFAULT:
    def __repr__(self):return "<no default>"
_NO_DEFAULT = _NO_DEFAULT()

def func(optional= _NO_DEFAULT):
    if optional is _NO_DEFAULT:
        print("the optional argument was not passed")
    else:
        print("the optional argument was:",optional)

alors tant que vous ne le faites pas, func(_NO_DEFAULT)vous pouvez détecter avec précision si l'argument a été passé ou non, et contrairement à la réponse acceptée, vous n'avez pas à vous soucier des effets secondaires de la notation **:

# these two work the same as using **
func()
func(optional=1)

# the optional argument can be positional or keyword unlike using **
func(1) 

#this correctly raises an error where as it would need to be explicitly checked when using **
func(invalid_arg=7)
Tadhg McDonald-Jensen
la source
Fais juste _NO_DEFAULT = object().
Aran-Fey
2 lignes supplémentaires pour une meilleure introspection en valent la peine. Avec cela, si vous exécutez, help(func)vous obtenez une idée plus claire de la façon dont l'argument est interprété s'il n'est pas passé explicitement.
Tadhg McDonald-Jensen