3

Let's say there's a function in a Python library (let's call it mymodule):

def some_func(a,b='myDefaultValue'):
    return some_computation

and then there's another function in another module that calls it,

import mymodule
def wrapper(a,b):
    return some_transform(mymodule.some_func(a,b))

How do I make it such that wrapper inherits some_func's default value for the b parameter? I could do something like:

def wrapper(a,b=None):
    if b:
        return some_transform(some_func(a,b))
    else:
        return some_transform(some_func(a))

but that seems needlessly cumbersome, leads to a combinatorial explosion of possibilities with multiple optional arguments, and makes it so I can't explicitly pass in None to wrapper.

Is there a way of getting the default args for a function, or is common practice to simply pull that value out into a shared constant that both function declarations can make use of?

2
  • 2
    What are you actually trying to do? There are different ways to do this sort of thing, and which one you should use depends on what exactly you're doing. Commented Aug 18, 2015 at 0:11
  • @Cyphase Thanks, I've updated the question a bit to hopefully make it more clear, while keeping it general. Commented Aug 18, 2015 at 5:20

3 Answers 3

2

You can use func_defaults: https://docs.python.org/2/library/inspect.html?highlight=func_defaults#types-and-members

func_defaults tuple of any default values for arguments

def some_func(a,b='myDefaultValue'):
    print a, b

def wrapper(a,b):
    b = some_func.func_defaults[0] if b is None else b
    some_func(a,b)


print "b is 'there'"
a = "hello"
b = "there"
wrapper(a,b)

print "b is 'None'"
b = None
wrapper(a,b)

output:

b is 'there'
hello there
b is 'None'
hello myDefaultValue

EDIT: To answer your question from the comments, there isn't anything built-in to look up the arguments of the function with default values by name. However, you know that the arguments with default values have to come after the non-optional arguments. So if you know the total number of arguments you have, and how many of them have default values, you can subtract the 2 to get the starting point of the arguments with default values. Then you can zip the list of arguments (starting at the previously calculated argument index) together with the list of default argument values and create a dictionary from the list. Use the inspect module to get all of the information you need:

Like so:

>>> import inspect
>>> def some_func(a,b,c,d="dee",e="ee"):
...     print a,b,c,d,e
... 
>>> some_func("aaa","bbb","ccc",e="EEE")
aaa bbb ccc dee EEE
>>> some_funcspec = inspect.getargspec(some_func)
>>> some_funcspec
ArgSpec(args=['a', 'b', 'c', 'd', 'e'], varargs=None, keywords=None, defaults=('dee', 'ee'))
>>> defargsstartindex = len(some_funcspec.args) - len(some_funcspec.defaults)
>>> defargsstartindex
3
>>> namedargsdict = dict(zip([key for key in some_funcspec.args[defargsstartindex:]], list(some_funcspec.defaults)))
>>> namedargsdict
{'e': 'ee', 'd': 'dee'}

In the example above, namedargsdict is your list of arguments with default values for some_func.

Further reading:

https://docs.python.org/2/library/inspect.html#inspect.getargspec

inspect.getargspec(func) Get the names and default values of a Python function’s arguments. A tuple of four things is returned: (args, varargs, keywords, defaults). args is a list of the argument names (it may contain nested lists). varargs and keywords are the names of the * and ** arguments or None. defaults is a tuple of default argument values or None if there are no default arguments; if this tuple has n elements, they correspond to the last n elements listed in args.

Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs, keywords, defaults).

Sign up to request clarification or add additional context in comments.

4 Comments

Ah, that's almost perfect. Is there any way to apply those to named parameters/kwargs?
Er, by that I mean, is there any way to be able to look up the parameter by name, rather than positionally? In the future the wrapped function could get more parameters added (or more defaults) and I'd like to not worry about the order getting messed up.
@fluffy I edited the answer to address your comments.
Thanks. Seems like incredible overkill for what I'm trying to do - I should have just gone with my original instinct and just pull out this value into a shared constant. :)
2

You can use argument unpacking to accomplish this:

In [1]: def some_func(a,b='myDefaultValue'):
   ...:     print a, b
   ...:

In [2]: def wrapper(a, *args, **kwargs):
   ...:     some_func(a, *args, **kwargs)
   ...:

In [3]: some_func('foo', 'bar')
foo bar

In [4]: some_func('baz')
baz myDefaultValue

In [5]: wrapper('foo', 'bar')
foo bar

In [6]: wrapper('baz')
baz myDefaultValue

If you plan to wrap multiple functions in this way, you might consider making wrapper a decorator:

In [1]: from functools import wraps

In [2]: def wrapper(func):
   ...:     @wraps(func)
   ...:     def decorated(a, *args, **kwargs):
   ...:         print 'wrapper invoked with a = {}'.format(a)
   ...:         return func(a, *args, **kwargs)
   ...:     return decorated
   ...:

In [3]: @wrapper
   ...: def some_func(a, b='myDefaultValue'):
   ...:     print a, b
   ...:

In [4]: some_func('foo', 'bar')
wrapper invoked with a = foo
foo bar

In [5]: some_func('baz')
wrapper invoked with a = baz
baz myDefaultValue

Comments

0

Your question is not clear enough. But as far as I understand from your question, you should use class so that you can easily share values among multiple functions inside the class

class SomeClass:

  def __init__(self, b='defaultvalue'):
    self.b = b

  def some_func(self, a, b):
    pass

  def wrapper(self, a):
    self.some_func(a, self.b)

1 Comment

That isn't at all what I'm trying to go for, so I'll try rephrasing the question. These functions aren't in the same module.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.