How to iterate over function arguments

53,478

Solution 1

locals() may be your friend here if you call it first thing in your function.

Example 1:

>>> def fun(a, b, c):
...     d = locals()
...     e = d
...     print e
...     print locals()
... 
>>> fun(1, 2, 3)
{'a': 1, 'c': 3, 'b': 2}
{'a': 1, 'c': 3, 'b': 2, 'e': {...}, 'd': {...}}

Example 2:

>>> def nones(a, b, c, d):
...     arguments = locals()
...     print 'The following arguments are not None: ', ', '.join(k for k, v in arguments.items() if v is not None)
... 
>>> nones("Something", None, 'N', False)
The following arguments are not None:  a, c, d

Answer:

>>> def foo(a, b, c):
...     return ''.join(v for v in locals().values() if v is not None)
... 
>>> foo('Cleese', 'Palin', None)
'CleesePalin'

Update:

'Example 1' highlights that we may have some extra work to do if the order of your arguments is important as the dict returned by locals() (or vars()) is unordered. The function above also doesn't deal with numbers very gracefully. So here are a couple of refinements:

>>> def foo(a, b, c):
...     arguments = locals()
...     return ''.join(str(arguments[k]) for k in sorted(arguments.keys()) if arguments[k] is not None)
... 
>>> foo(None, 'Antioch', 3)
'Antioch3'

Solution 2

def func(*args):
    ' '.join(i if i is not None else '' for i in args)

if you're joining on an empty string, you could just do ''.join(i for i in args if i is not None)

Solution 3

You can use the inspect module and define a function like that:

import inspect
def f(a,b,c):
    argspec=inspect.getargvalues(inspect.currentframe())
    return argspec
f(1,2,3)
ArgInfo(args=['a', 'b', 'c'], varargs=None, keywords=None, locals={'a': 1, 'c': 3, 'b': 2})

in argspec there are all the info you need to perform any operation with argument passed.

To concatenate the string is sufficient to use the arg info received:

def f(a,b,c):
    argspec=inspect.getargvalues(inspect.currentframe())
    return ''.join(argspec.locals[arg] for arg in argspec.args)

For reference: http://docs.python.org/library/inspect.html#inspect.getargvalues

Solution 4

Is this perhaps what you'd like?

def foo(a, b, c):
    "SilentGhost suggested the join"
    ' '.join(i if i is not None else '' for i in vars().values())

def bar(a,b,c): 
    "A very usefull method!"
    print vars()
    print vars().values()

Notice the use of vars(), which returns a dict.

Share:
53,478

Related videos on Youtube

jackhab
Author by

jackhab

Updated on October 11, 2020

Comments

  • jackhab
    jackhab over 3 years

    I have a Python function accepting several string arguments def foo(a, b, c): and concatenating them in a string. I want to iterate over all function arguments to check they are not None. How it can be done? Is there a quick way to convert None to ""?

    Thanks.

  • jackhab
    jackhab about 14 years
    What if all the arguments are explicitly declared? Like in def foo(a, b, c):
  • SilentGhost
    SilentGhost about 14 years
    @Jack: re-define your function. That would be the easiest option. If you have only few arguments, you could put them into a tuple.
  • SilentGhost
    SilentGhost about 14 years
    @Jack: why do you think so? it's idiomatic Python. Do you use your arguments individually? If you you could easily unpack args into variables with appropriate names.
  • extraneon
    extraneon about 14 years
    @Jack I agree with you there. You could explicitly name your arguments, and build a list of those args before joining (args = [a,b,c]). Perhaps a keyword construct is also a solution; you could then get the values from the kwargs dict. Keyword default values can however have unexpected behavior.
  • jackhab
    jackhab about 14 years
    @extraneon I started with Python two days ago and I'm not sure I understand what you mean.
  • jackhab
    jackhab about 14 years
    I thought the arguments passed to function in some sort of dictionary and this dictionary can be accessed via some built-in attribute or something. EDIT: Oh! just found it - it's called locals()
  • SilentGhost
    SilentGhost about 14 years
    @Jack: it's not clear what would be the best option for you because you're not showing us how exactly you're using those arguments. Are you using the a, b and c in any other way?
  • John La Rooy
    John La Rooy about 14 years
    I think None means the python object None not the literal string "None"
  • johnsyweb
    johnsyweb about 14 years
    FWIW, I think that *args is the way to go here... what if you want to concatenate sixteen strings? I just wanted to show that it was possible in Python using the function signature provided :-)
  • extraneon
    extraneon about 14 years
    @Jack def func(a,b,c): args=[a,b,c] ' '.join(i if i is not None else '' for i in args)
  • extraneon
    extraneon about 14 years
    in stead of locals you can also use vars().
  • johnsyweb
    johnsyweb about 14 years
    @extraneon Thanks for the tip. locals() seems to behave the same as vars() with no arguments in this case.
  • Darren Ringer
    Darren Ringer almost 8 years
    Found this very useful along with a function that converts underscore-separated strings into camelcase ones... can save a lot of tedious boilerplate code when instantiating object attributes from the init parameters. I'm still waiting to get myself into trouble with this style of programming :P
  • Stevoisiak
    Stevoisiak over 6 years
    To simplify the example, it may help to split up the statements onto separate lines. (ie: for k in sorted(arguments.keys()): if arguments[k] is not None: print(str(arguments[k])))
  • Darren Ringer
    Darren Ringer over 6 years
    @StevenVascellaro I saw you had asked for that function I mentioned above; not sure if you still want to see it (and it isn't that great anyway) but it is found here: github.com/dwringer/misc/blob/master/utils.py#L438-L465
  • hugovdberg
    hugovdberg almost 4 years
    For joining the string *args might be cleaner, but I think using locals is very useful if you want the keywords as well. For example to compile parameters to an URL from keyword arguments, of which several might be optional. This way you can explicitly state which parameters are available, and at the same time only relay the provided parameters to the URL.