Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check whether optional function parameter is set

Is there an easy way in Python to check whether the value of an optional parameter comes from its default value, or because the user has set it explicitly at the function call?

like image 937
Matthias Avatar asked Feb 07 '13 10:02

Matthias


People also ask

How do I know if optional parameter exists in darts?

The Dart-Homepage shows following: It turns out that Dart does indeed have a way to ask if an optional parameter was provided when the method was called. Just use the question mark parameter syntax.

How do I set optional parameters?

Using Optional Attribute Here for the [Optional] attribute is used to specify the optional parameter. Also, it should be noted that optional parameters should always be specified at the end of the parameters. For ex − OptionalMethodWithDefaultValue(int value1 = 5, int value2) will throw exception.

Which method check whether a parameter is explicitly set by user?

Just do 'a' in explicit_params to check if parameter a is given explicitly.


2 Answers

Not really. The standard way is to use a default value that the user would not be expected to pass, e.g. an object instance:

DEFAULT = object() def foo(param=DEFAULT):     if param is DEFAULT:         ... 

Usually you can just use None as the default value, if it doesn't make sense as a value the user would want to pass.

The alternative is to use kwargs:

def foo(**kwargs):     if 'param' in kwargs:         param = kwargs['param']     else:         ... 

However this is overly verbose and makes your function more difficult to use as its documentation will not automatically include the param parameter.

like image 83
ecatmur Avatar answered Sep 18 '22 22:09

ecatmur


Lot of answers have little pieces of the full info, so I'd like to bring it all together with my favourite pattern(s).

default value is a mutable type

If the default value is a mutable object, you are lucky: you can exploit the fact that Python’s default arguments are evaluated once when the function is defined (some more about this at the end of the answer in the last section)

This means you can easily compare a default mutable value using is to see if it was passed as an argument or left by default, as in the following examples as function or method:

def f(value={}):     if value is f.__defaults__[0]:         print('default')     else:         print('passed in the call') 

and

class A:     def f(self, value={}):         if value is self.f.__defaults__[0]:             print('default')         else:             print('passed in the call') 

Immutable default arguments

Now, it's a bit less elegant if your default is expected to be an immutable value (and remember that even strings are immutable!) because you can't exploit the trick as it is, but there is still something you can do, still exploiting mutable type; basically you put a mutable "fake" default in the function signature, and the desired "real" default value in the function body.

def f(value={}):     """     my function     :param value: value for my function; default is 1     """     if value is f.__defaults__[0]:         print('default')         value = 1     else:         print('passed in the call')     # whatever I want to do with the value     print(value) 

It feels particularly funny if you real default is None, but None is immutable so... you still need to explicitly use a mutable as the function default parameter, and switch to None in the code.

Using a Default class for immutable defaults

or, similar to @c-z suggestion, if python docs are not enough :-) , you can add an object in between to make the API more explicit (without reading the docs); the used_proxy_ Default class instance is mutable, and will contain the real default value you want to use.

class Default:     def __repr__(self):         return "Default Value: {} ({})".format(self.value, type(self.value))      def __init__(self, value):         self.value = value  def f(default=Default(1)):     if default is f.__defaults__[0]:         print('default')         print(default)         default = default.value     else:         print('passed in the call')     print("argument is: {}".format(default)) 

now:

>>> f() default Default Value: 1 (<class 'int'>) argument is: 1  >>> f(2) passed in the call argument is: 2 

The above works nicely also for Default(None).

Other patterns

Obviously the above patterns looks uglier than they should because of all the print which are there only for showing how they work. Otherwise I find them terse and repeatable enough.

You could write a decorator to add the __call__ pattern suggested by @dmg in a more streamlined way, but this will still oblige to use weird tricks in the function definition itself - you would need to split out value and value_default if your code need to distinguish them, so I don't see much advantage and I won't write the example :-)

Mutable types as default values in Python

A bit more about #1 python gotcha!, abused for your own pleasure above. You can see what happens due to the evaluation at definition by doing:

def testme(default=[]):     print(id(default)) 

You can run testme() as many time as you want, you will always see a reference to the same default instance (so basically your default is immutable :-) ).

Remember that in Python there are only 3 mutable built-in types: set, list, dict; everything else - even strings! - is immutable.

like image 25
Stefano Avatar answered Sep 17 '22 22:09

Stefano