Home > Blockchain >  Conditionally including multiple keyword arguments in a function call
Conditionally including multiple keyword arguments in a function call

Time:01-16

What is the 'pythonic' way to implement a waterfall if-statement like situation like this, when it applies to kwargs? I'm trying to avoid a situation where c=None is added to kwargs (because having c in the kwargs keys causes all sorts of problems downstream).

def run_something(**kwargs):
    print(kwargs)

def func(a = None, b=None, c=None):
    
    if a and b and c:
        run_something(a=a,b=b,c=c)
    elif a and b:        
        run_something(a=a,b=b)
    elif a:
        run_something(a=a)
    else:
        run_something()

I know the easy answer is that I could just do:

def func(**kwargs): 
    run_something(**kwargs)

however my particular use case doesn't make this easy

CodePudding user response:

First of all, instead of doing tests like if a: I am guessing what you really want to do is only pass the a argument of it isn't None so testing if a is not None: will pass a value for a that is 0 or an empty string, i.e. anything other than the default. So this is what I would do:

def run_something(**kwargs):
    print(kwargs)

def func(a = None, b=None, c=None):
    d = {}
    if a is not None:
        d['a'] = a
    if b is not None:
        d['b'] = b
    if c is not None:
        d['c'] = c
    run_something(**d)

func(c=7, b=4)

Prints:

{'b': 4, 'c': 7}

Note that the above handles any combination of passed arguments, which your "waterfall" if statements do not. If you really want to test for any non-False value as in your original code, then of course you can do:

def run_something(**kwargs):
    print(kwargs)

def func(a=None, b=None, c=None):
    d = {}
    if a:
        d['a'] = a
    if b:
        d['b'] = b
    if c:
        d['c'] = c
    run_something(**d)

func(c=7, b=4)

CodePudding user response:

You can do something like this:

def run_something(**kwargs):
    print(kwargs)


def func(a=None, b=None, c=None):
    kwargs = {"a": a, "b": b, "c": c}
    run_something(**{key_word: arg for key_word, arg in kwargs.items() if arg is not None})


func()                  # {}
func("a")               # {'a': 'a'}
func("a", "b")          # {'a': 'a', 'b': 'b'}
func("a", "b", "c")     # {'a': 'a', 'b': 'b', 'c': 'c'}
func(b="b")             # {'b': 'b'}
func("a", c="c")        # {'a': 'a', 'c': 'c'}
func(b="b", c="c")      # {'b': 'b', 'c': 'c'}
func(c="c")             # {'c': 'c'}

this will handle any combination of a b and c

I used dictionary comprehension. in case you don't know what it means you can check this out python dictionary comprehension

CodePudding user response:

Short and sweet:

def foo(a=None, b=None, c=None):
    run_something(
        **({ 'a': a } if a else {}),
        **({ 'b': b } if b else {}),
        **({ 'c': c } if c else {}),
    )

Whether it’s ‘pythonic’, I will not say. Personally, I find it a meaningless notion, vague and ad-hoc at best and self-contradictory at worst.

  • Related