6
def function(varone=None, vartwo=None, varthree=None):
     values = {}
            if var1 is not None:   
                    values['var1'] = varone
            if var2 is not None:
                    values['var2'] = vartwo
            if var3 is not None:
                    values['var3'] = varthree
            if not values:
                    raise Exception("No values provided")

Can someone suggest a more elegant, pythonic way to accomplish taking placing non-null named variables and placing them in a dictionary? I do not want the values to be passed in as a dictionary. The key names of "values" are important and must be as they are. The value of "varone" must go into var1, "vartwo" must go into var2 and so on; Thanks.

Jaigus
  • 1,422
  • 1
  • 16
  • 31

4 Answers4

8

You could use kwargs:

def function(*args, **kwargs):
    values = {}
    for k in kwargs:
        if kwargs[k] is not None:
            values[k] = kwargs[k]
    if not values:
        raise Exception("No values provided")
    return values

>>> function(varone=None, vartwo="fish", varthree=None)
{'vartwo': 'fish'}

With this syntax, Python removes the need to explicitly specify any argument list, and allows functions to handle any old keyword arguments they want.

If you're specifically looking for keys var1 etc instead of varone you just modify the function call:

>>> function(var1=None, var2="fish", var3=None)
{'var2': 'fish'}

If you want to be REALLY slick, you can use list comprehensions:

def function(**kwargs):
    values = dict([i for i in kwargs.iteritems() if i[1] != None])
    if not values:
        raise Exception("foo")
    return values

Again, you'll have to alter your parameter names to be consistent with your output keys.

atomicinf
  • 3,596
  • 19
  • 17
  • 1
    +1 for the list comprehension (or it could be a dict comprehension in newer versions of Python) – David Z Oct 27 '12 at 06:39
4

Use **kwargs. Example:

def function(**kwargs):
    if not kwargs:
        raise Exception("No values provided")
    for k, v in kwargs.items():
        print("%s: %r") % (k, v)

If you really are going to call function with None arguments, you can strip them out:

def function(**kwargs):
    for k, v in kwargs.items():
        if v is None:
            del kwargs[k]
    if not kwargs:
        raise Exception("No values provided")
    for k, v in kwargs.items():
        print("%s: %r") % (k, v)

Obviously you could call the dict values instead, but kwargs is the conventional name, and will make your code more intelligible to other people.

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • It's probably cleaner to just skip printing the `None`s, rather than removing them from the dictionary beforehand. – David Z Oct 27 '12 at 06:38
  • But to work the same way as the function in the question is intended to, it needs to raise an exception if there are no non-None arguments ... – Zero Piraeus Oct 27 '12 at 06:43
  • OK, well, you could just keep a boolean flag indicating whether any non-`None` items were encountered (and printed), and raise the exception if the flag is not set after the loop. – David Z Oct 27 '12 at 06:45
  • I suppose ... but the print loop at the end is really just so that the function does something, anything. Actually answering the question is better solved like this, I think. – Zero Piraeus Oct 27 '12 at 06:48
  • Why does the function have to do something? And in any case, it is already doing something, namely filtering the arguments. I do not agree that this is a better answer to the question. – David Z Oct 27 '12 at 06:50
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18652/discussion-between-david-zaslavsky-and-zero-piraeus) – David Z Oct 27 '12 at 06:52
2

Well, you can pass all those values inside a keyword argument: -

def function(*nkwargs, **kwargs):
    values = {}

    for k in kwargs:
        if kwargs[k] is not None:
            values[k] = kwargs[k]
    if not values:
        raise Exception("No values")
    print values

try:
    function()
except Exception, e:
    print e

function(varOne=123, varTwo=None)
function(varOne=123, varTwo=234)

OUTPUT: -

No values
{'varOne': 123}
{'varOne': 123, 'varTwo': 234}
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
1

Call your function as usual, but accept as **kwargs. Then filter them:

def fn(**kwargs):
    items = {'var%s' % i: v for i, (k, v) in enumerate(items)}

fn(a=1, b=2, c=3)

if you need a specific set of names, then make a dict of names:

    names = dict(zip('varOne varTwo varThree'.split(), range(1, 4)))

walk over this dict and check if the var is in kwargs:

items = {'var%s' % k: kwargs[v] for k, v in names.items() if v in kwargs}
culebrón
  • 34,265
  • 20
  • 72
  • 110