views:

141

answers:

5

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.

+8  A: 
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)

SilentGhost
What if all the arguments are explicitly declared? Like in def foo(a, b, c):
Jack
@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
But this make the code less readable
Jack
@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.
SilentGhost
@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.
extraneon
@extraneon I started with Python two days ago and I'm not sure I understand what you mean.
Jack
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()
Jack
@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?
SilentGhost
@Jack def func(a,b,c): args=[a,b,c] ' '.join(i if i is not None else '' for i in args)
extraneon
A: 

I would use sed s/None//g, but that's not in python, but you can probably use os.popen() to do that.

Ernst
What if SilentGhosts on Windows.....not v pythonic....:-)
Ben Hughes
I think `None` means the python object `None` not the literal string `"None"`
gnibbler
+4  A: 

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'
Johnsyweb
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 :-)
Johnsyweb
@Johnsyweb in stead of locals you can also use vars().
extraneon
@extraneon Thanks for the tip. `locals()` seems to behave the same as `vars()` with no arguments in this case.
Johnsyweb
+2  A: 

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

pygabriel
A: 

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.

extraneon