d3pd
d3pd

Reputation: 8295

What is a good way to get a function to use its default value for an argument when the argument is specified as None in Python?

Let's say I have a function (called function) that takes a boolean argument with default value of True like def function(argument1 = True).

Now let's say I want to use this function, specifying its argument using the output of another function (resolveArg) that checks for arguments in an existing infrastructure. This resolveArg method is used generally and if it can find the argument value destined for a given function (e.g. function), then it sets the function argument to it, otherwise it sets the argument to None.

How can I get function to use the default value of its argument if its argument is set to None by this other function (resolveArg)?

def resolveArg(argName = None):
    if argName in self.conf._argdict:
        return(self.conf._argdict[argName].value)
    else:
        return(None)

def function(argument1 = True)
    if argument1 is True:
        return(True)
    elif argument1 is False:
        return(False)
    else:
        raise(Exception)

function(argument1 = resolveArg("red"))

Upvotes: 2

Views: 192

Answers (4)

Jadav Bheda
Jadav Bheda

Reputation: 5311

Probably you want to modify your implementation of function little bit as follow:

def function(argument1 = None)
    if argument1 is None:
       argument1 = True        

    return argument1

If you want to understand more about default function argument as None, you may want to refer to my other SO answer

Upvotes: 0

J Richard Snape
J Richard Snape

Reputation: 20344

Caveat

You asked for a "good way to get a function to use its default value for an argument when the argument is specified as None in Python?"

I would argue that there isn't a good way, because it's not a good thing to do. This is a risky thing to do - it can mask nasty error cases where you might reasonably want to detect the fact that None was passed in where you expected a value. Debugging where this technique is used extensively could be horrible. Use with extreme caution.

Possible method

I'm guessing you want a generic solution that will work for more functions than the one you offer as an example. In the example case - you would be easiest to simply test for None in the argument value and replace it if necessary.

You could write a decorator to do the general case, that will use the inspect toolbox to work out the argument values across the list of arguments with default values and replace them if they are None.

The code below demonstrates the idea with some simple test cases - this will work, but only for functions with simple arguments (not *args, **kwargs) as currently constituted. It could be enhanced to cover those cases. It safely treats arguments without defaults as usual.

Python Fiddle

import inspect

def none2defaultdecorator(thisfunc):
    (specargs, _, _, defaults) = inspect.getargspec(thisfunc)

    def wrappedfunc(*instargs):        
        callargs = inspect.getcallargs(thisfunc, *instargs)

        if len(specargs) != len(callargs):
             print "Strange - different argument count in this call to those in spec"
             print specargs
             print callargs

        for i,argname in enumerate(specargs[-len(defaults):]):
            try:
                if callargs[argname] == None:
                    callargs[argname] = defaults[i]
            except KeyError:
                # no local value for this argument - it will get the default anyway
                pass

        return thisfunc(**callargs)

    return wrappedfunc

#Decorate the funtion with the "None replacer".  Comment this out to see difference
@none2defaultdecorator            
def test(binarg = True, myint = 5):
    if binarg == True:
        print "Got binarg == true"
    elif binarg == False:
        print "Got binarg == false"
    else:
        print "Didn't understand this argument - binarg == ", binarg

    print "Argument values - binarg:",binarg,"; myint:",myint

test()
test(False)
test(True)
test(None)
test(None, None)

Upvotes: 1

Lachezar
Lachezar

Reputation: 6703

I have not seen this kind of problem before, so may be there is a way to improve your logic and omit this functionality.

However there is a way to do introspection of code in Python by using the module "inspect".

An example usage is:

>>> def a(q=5):
...  if q is None:
...   return dict(inspect.getmembers(a))['func_defaults'][0]
...  return q
...
>>> a()
5
>>> a(None)
5

The problem with this is that "func_defaults" returns a list which is inconvenient in case you have multiple argument function and as a whole makes the procedure error prone.

Upvotes: 1

El Bert
El Bert

Reputation: 3026

One way would be to give the same behavior to yourfunction if the argument is True or None.

def function(arg=True):
    if arg in [True, None]:
        do_stuff()
    else:
        do_something_else()

Upvotes: 0

Related Questions