views:

489

answers:

5

I would like to know if it is possible to determine if a function parameter with a default value was passed in Python. For example, how does dict.pop work?

>>> {}.pop('test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'pop(): dictionary is empty'
>>> {}.pop('test',None)
>>> {}.pop('test',3)
3
>>> {}.pop('test',NotImplemented)
NotImplemented

How does the pop method determine that the first time a default return value was not passed? Is this something that can only be done in C?

Thanks

+1  A: 

You can do it like this:

def isdefarg(*args):
    if len(args) > 0:
        print len(args), "arguments"
    else:
        print "no arguments"

isdefarg()
isdefarg(None)
isdefarg(5, 7)

See the Python documentation on calls for full information.

Greg Hewgill
+5  A: 

I guess you mean "keyword argument", when you say "named parameter". dict.pop() does not accept keyword argument, so this part of the question is moot.

>>> {}.pop('test', d=None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pop() takes no keyword arguments

That said, the way to detect whether an argument was provided is to use the *args or **kwargs syntax. For example:

def foo(first, *rest):
    if len(rest) > 1:
        raise TypeError("foo() expected at most 2 arguments, got %d"
                        % (len(rest) + 1))
    print 'first =', first
    if rest:
        print 'second =', rest[0]

With some work, and using the **kwargs syntax too it is possible to completely emulate the python calling convention, where arguments can be either provided by position or by name, and arguments provided multiple times (by position and name) cause an error.

ddaa
+1  A: 
def f(one, two=2):
   print "I wonder if", two, "has been passed or not..."

f(1, 2)

If this is the exact meaning of your question, I think that there is no way to distinguish between a 2 that was in the default value and a 2 that has been passed. I didn't find how to accomplish such distinction even in the inspect module.

Federico Ramponi
+1  A: 

I am not certain if I fully understand what is it you want; however:

def fun(arg=Ellipsis):
    if arg is Ellipsis:
        print "No arg provided"
    else:
        print "arg provided:", repr(arg)

does that do what you want? If not, then as others have suggested, you should declare your function with the *args, **kwargs syntax and check in the kwargs dict for the parameter existence.

ΤΖΩΤΖΙΟΥ
+2  A: 

The convention is often to use arg=None and use

def foo(arg=None):
    if arg is None:
        arg = "default value"
        # other stuff
    # ...

to check if it was passed or not. Allowing the user to pass None, which would be interpreted as if the argument was not passed.

MizardX