Existe-t-il un moyen simple en Python de vérifier si la valeur d'un paramètre optionnel provient de sa valeur par défaut, ou parce que l'utilisateur l'a défini explicitement à l'appel de la fonction ?
Réponses
Trop de publicités?La réponse de @Ellioh fonctionne dans python 2. En python 3, le code suivant devrait fonctionner :
import inspect
from functools import wraps
def explicit_checker(f):
varnames = inspect.getfullargspec(f)[0]
@wraps(f)
def wrapper(*a, **kw):
kw['explicit_params'] = set(list(varnames[:len(a)]) + list(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
Cette méthode peut conserver les noms des arguments et les valeurs par défaut (au lieu de **kwargs) avec une meilleure lisibilité.
Je suis d'accord avec le commentaire de Volatility. Mais vous pourriez 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 consulter à partir de foo.__defaults__
y 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 =
y is
vous pouvez les comparer
et pour certains cas, le code ci-dessous est suffisant
Par exemple, si vous devez éviter de modifier la valeur par défaut, vous pouvez vérifier l'égalité et, le cas échéant, la copier.
def update_and_show(data=Example):
if data is Example:
data = copy.deepcopy(data)
update_inplace(data) #some operation
print(data)
Il est également très pratique à utiliser getcallargs
de inspect
car il renvoie des arguments réels avec lesquels la fonction sera invoquée. Vous passez une fonction et des args et kwargs à celle-ci ( inspect.getcallargs(func, /, *args, **kwds)
), il retournera les arguments réels de la méthode utilisés pour l'invocation, en tenant compte des valeurs par défaut et d'autres éléments. Regardez l'exemple ci-dessous.
from inspect import getcallargs
# we have a function with such signature
def show_params(first, second, third=3):
pass
# if you wanted to invoke it with such params (you could get them from a decorator as example)
args = [1, 2, 5]
kwargs = {}
print(getcallargs(show_params, *args, **kwargs))
#{'first': 1, 'second': 2, 'third': 5}
# here we didn't specify value for d
args = [1, 2, 3, 4]
kwargs = {}
# ----------------------------------------------------------
# but d has default value =7
def show_params1(first, *second, d = 7):
pass
print(getcallargs(show_params1, *args, **kwargs))
# it will consider b to be equal to default value 7 as it is in real method invocation
# {'first': 1, 'second': (2, 3, 4), 'd': 7}
# ----------------------------------------------------------
args = [1]
kwargs = {"d": 4}
def show_params2(first, d=3):
pass
print(getcallargs(show_params2, *args, **kwargs))
#{'first': 1, 'd': 4}
Une approche un peu bizarre 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()
Quelles sorties :
passed default
z
passed different
b
not passed
z
Comme je l'ai dit, c'est assez bizarre, mais ça fait l'affaire. Cependant, c'est assez illisible et, comme dans le cas de ecatmur 's suggestion ne seront pas automatiquement documentés.
- Réponses précédentes
- Plus de réponses