python named arguments auto-naming

Go To StackoverFlow.com

0

So if I have a function which takes loads of named arguments:

def foo(a = 1, b = 2, c = 3, d = 4, e = 5) # etc...
    pass

and I'm calling it with all the arguments having exactly the same names as in the definition:

a = 0
b = 0
c = 0
d = 0
e = 0

is there a way to avoid doing this?

foo(e = e, b = b, d = d, a = a, c = c)

and just do this:

foo(e, b, d, a, c)

?

I guess I can do this:

foo(a, b, c, d, e)

but what if the arguments have complicated names and I can't remember the order of them by heart?

2012-04-05 16:37
by Ferguzz
Why not simply foo(e=0, b=0, d=0, a=0, c=0) - Sven Marnach 2012-04-05 16:39
because a, b etc. might be defined within if conditions etc - Ferguzz 2012-04-05 16:40
Can you change foo - Marc-Olivier Titeux 2012-04-05 16:42
unfortunately no - Ferguzz 2012-04-05 16:43
@Ferguzz: Well, for those that need more complicated code, use a=a, for the other ones use b=0 - Sven Marnach 2012-04-05 16:44
The correct answer is to have less parameters. If you need help seeing how to do that, post your code on codereview.stackexchange.com. Anything else you can do will only make it worse in the long run - Winston Ewert 2012-04-05 16:51
strange that this question got a -1? code examples, clear question. what is wrong with it - Ferguzz 2012-04-05 16:56
@Ferguzz, you've probably gotten downvoted because it looks like you are trying to abuse the language rather then fix the interface - Winston Ewert 2012-04-05 17:14


5

Well, you could do something like:

def foo(a, b, c, d):
    print a, b, c, d


d = 4
b = 2
c = 3
a = 1

import inspect
foo(*[locals().get(arg, None) for arg in inspect.getargspec(foo).args])

but I'm not sure I can recommend this... In practice I'd use a dictionary of arguments:

foo_params = {
    'd' : 4,
    'b' : 2,
    'c' : 3,
    'a' : 1
}

foo(**foo_params)

of write a wrapper for foo which uses less arguments.

2012-04-05 16:50
by georg
Yes, you could do that, but then someone would probably have to kill you - Daniel Roseman 2012-04-05 16:51
Moreover, this breaks for many real-world functions that use **kwargs - Sven Marnach 2012-04-05 16:51
thanks. I think i'll just stick to looking up the order though - Ferguzz 2012-04-05 16:52
@DanielRoseman: this code answers the question exactly as asked. If you know a better way ("don't do that" doesn't count), feel free to share - georg 2012-04-05 16:59
A dict is the way to go, without the bad code part you would get more upvote - Jochen Ritzel 2012-04-05 17:12


3

Python's argument passing mechanisms are extremely flexible. If they're not flexible enough, this seems like a design smell to me ...

  • possible smell: too many arguments to a function. Solutions: split into multiple functions, pass some args together in a dictionary or object.

  • possible smell: bad variable names. Solution: give variables more descriptive names.

Or just bite the bullet, figure out the correct order, and keep it simple.

2012-04-05 16:53
by Matt Fenwick
He said he didn't write that function - georg 2012-04-05 16:55
@thg435 he/she could still improve the variable names outside of fooMatt Fenwick 2012-04-05 16:56


3

If changing the function is not an option for you but you have the liberty to change the methodology in which you are assigning value to the parameters passed, here is a example code that might be helpful to you. This used orderdict to preserv the

Given

>>> def foo(a = 1, b = 2, c = 3, d = 4, e = 5):
    print "a={0},b={1},c={2},d={3},e={4}".format(a,b,c,d,e)

the you can do

>>> var=dict()
>>> var['c']=12
>>> var['a']=10
>>> var['b']=11
>>> var['e']=14
>>> foo(**var)
a=10,b=11,c=12,d=4,e=14

Note, this answer is similar to what was proposed by @thg435 but you are

  1. Not using inspect to hack the arguments a function expects.
  2. Not looking through the local/global dictionary.
  3. Supports missing arguments which defaults to what is the default argument.
  4. And off-course you do not have to remember the order.
  5. And you don;t even have to pass the variables as parameters. Just pass the dictionary.
2012-04-05 17:12
by Abhijit


0

You can do the following:

def func(a=1, b=2, c=3, **kw):
    print a,b,c

a = 11
b = 22
c = 33

func(**locals())
2012-04-05 16:51
by sega_sai
The OP cannot change foo() (or func(), respectively) - Sven Marnach 2012-04-05 16:53


0

Calling a 5-argument function with a completely different set of arguments each time is pretty rare. If, in practice, you're using the same a, c, and e args most of the time and calling with different b and d args (for example), you can create a class to help you with this:

class FooWrapper(object):
    def __init__( self, commonA, commonC, commonE ):
        self.a = commonA
        self.c = commonC
        self.e = commonE

    def invokeFoo( self, _b, _d ):
        foo( a=self.a, b = _b, c = self.c, d = _d, e = self.e )

w = FooWrapper( 1, 2, 3 )
w.invokeFoo( 4, 5 )          # calls foo( 1, 4, 2, 5, 3 )
w.invokeFoo( 6, 7 )          # calls foo( 1, 6, 2, 7, 3 )
2012-04-05 18:00
by Russell Borogove
This is basically what functools.partial does - georg 2012-04-05 18:02
Ads