Python: Comment vérifier si le paramètre optionnel de la fonction est défini
7 réponses
pas vraiment. La norme est d'utiliser une valeur par défaut que l'utilisateur ne devrait pas passer, par exemple, un object
exemple:
DEFAULT = object()
def foo(param=DEFAULT):
if param is DEFAULT:
...
habituellement, vous pouvez simplement utiliser None
comme valeur par défaut, si cela n'a pas de sens comme valeur que l'utilisateur voudrait passer.
l'alternative est d'utiliser kwargs
:
def foo(**kwargs):
if 'param' in kwargs:
param = kwargs['param']
else:
...
cependant ceci est trop verbeux et rend votre fonction plus difficile à l'utilisation comme documentation n'inclut pas automatiquement le paramètre param
.
le décorateur de fonction suivant, explicit_checker
, fait un ensemble de noms de paramètre de tous les paramètres donnés explicitement. Il ajoute le résultat comme paramètre supplémentaire ( explicit_params
) à la fonction. Il suffit de faire 'a' in explicit_params
pour vérifier si le paramètre a
est donné explicitement.
def explicit_checker(f):
varnames = f.func_code.co_varnames
def wrapper(*a, **kw):
kw['explicit_params'] = set(list(varnames[:len(a)]) + kw.keys())
return f(*a, **kw)
return wrapper
@explicit_checker
def my_function(a, b=0, c=1, explicit_params=None):
print a, b, c, explicit_params
if 'b' in explicit_params:
pass # Do whatever you want
my_function(1)
my_function(1, 0)
my_function(1, c=1)
j'utilise parfois une chaîne unique universellement (comme un UUID).
import uuid
DEFAULT = uuid.uuid4()
def foo(arg=DEFAULT):
if arg is DEFAULT:
# it was not passed in
else:
# it was passed in
de cette façon , Aucun utilisateur ne pourrait même deviner la valeur par défaut s'ils essayaient donc je peux être très sûr que lorsque je vois cette valeur pour arg
, il n'a pas été passé.
Je suis d'accord avec le commentaire de Volatility. Mais vous pouvez vérifier, de la manière suivante:
def function(arg1,...,**optional):
if 'optional_arg' in optional:
# user has set 'optional_arg'
else:
# user has not set 'optional_arg'
optional['optional_arg'] = optional_arg_default_value # set default
vous pouvez le vérifier à partir de foo.__defaults__
et foo.__kwdefaults__
voir un exemple simple ci-dessous
def foo(a, b, c=123, d=456, *, e=789, f=100):
print(foo.__defaults__)
# (123, 456)
print(foo.__kwdefaults__)
# {'e': 789, 'f': 100}
print(a, b, c, d, e, f)
#and these variables are also accessible out of function body
print(foo.__defaults__)
# (123, 456)
print(foo.__kwdefaults__)
# {'e': 789, 'f': 100}
foo.__kwdefaults__['e'] = 100500
foo(1, 2)
#(123, 456)
#{'f': 100, 'e': 100500}
#1 2 123 456 100500 100
puis en utilisant l'opérateur =
et is
vous pouvez les comparer
et, dans certains cas, le code ci-dessous est utilisé
par exemple, vous devez éviter de changer la valeur par défaut alors vous pouvez vérifier l'égalité et puis faire face si oui
def update_and_show(data=Example):
if data is Example:
data = copy.deepcopy(data)
update_inplace(data) #some operation
print(data)
Un peu fantasque approche serait:
class CheckerFunction(object):
def __init__(self, function, **defaults):
self.function = function
self.defaults = defaults
def __call__(self, **kwargs):
for key in self.defaults:
if(key in kwargs):
if(kwargs[key] == self.defaults[key]):
print 'passed default'
else:
print 'passed different'
else:
print 'not passed'
kwargs[key] = self.defaults[key]
return self.function(**kwargs)
def f(a):
print a
check_f = CheckerFunction(f, a='z')
check_f(a='z')
check_f(a='b')
check_f()
qui produit:
passed default
z
passed different
b
not passed
z
maintenant ceci, comme je l'ai mentionné, est assez effrayant, mais il fait le travail. Toutefois, ceci est tout à fait illisible et de la même manière que ecatmur 's suggestion ne sera pas automatiquement documentée.
j'ai vu ce modèle à quelques reprises (par exemple bibliothèque unittest
, py-flags
, jinja
):
class Default:
def __repr__( self ):
return "DEFAULT"
DEFAULT = Default()
...ou l'équivalent one-liner...:
DEFAULT = type( 'Default', (), { '__repr__': lambda x: 'DEFAULT' } )()
contrairement à DEFAULT = object()
, cela facilite la vérification de type et fournit de l'information lorsque des erreurs se produisent -- souvent, la représentation de chaîne ( "DEFAULT"
) ou le nom de classe ( "Default"
) sont utilisés dans les messages d'erreur.