5

Is it possible to simplify the boolean check of a kwargs option?

For example in foo I have to check lots of options:

def foo(*args, **kwargs):
   if 'foo' in kwargs and kwargs['foo'] is True:
      do_something()
   if 'bar' in kwargs and kwargs['bar'] is True:
      do_something_else()
   ...

One possible workaroud is to hide some complexity by adding more complexity...

def parse_kwargs(kwords, **kwargs):
   keywords = {}
   for kw in kwords:
      keywords[kw] = True if kw in kwargs and kwargs['kw'] is True else False
   return keywords

Then in my main function:

def foo(*args, **kwargs):
   kw = parse_kwargs(**kwargs)

   if kw['foo']:
      do_something()
   if kw['bar']:
      do_something_else()
   ...

I would like to know if I can use a simpler method less boilerplate...

nowox
  • 25,978
  • 39
  • 143
  • 293

3 Answers3

7

dict.get is useful to avoid the KeyError when accessing a non-existent key:

if kwargs.get('foo'):

Or

if kwargs.get('foo', False):
chepner
  • 497,756
  • 71
  • 530
  • 681
shx2
  • 61,779
  • 13
  • 130
  • 153
1

How about this?

def foo(*args, **kwargs):
   keywords = {'foo': do_foo_something,
               'bar': do_bar_something,
               'frug': do_frug_someting,
               ...}
   for k in keywords:
      if kwargs.get(k, False):
         keywords[k]()

def do_foo_something():
   do stuff

def do_bar_something():
   do stuff

def do_frug_something():
   do stuff
Tom Barron
  • 1,554
  • 18
  • 23
  • Hmmm... Useful technique to simplify the code. Nice work! :D – Zizouz212 Dec 06 '15 at 20:07
  • This is a good answer to this very question, but I was actually trying to avoid `KeyError` as [shx2](http://stackoverflow.com/users/2096752/shx2) found it. – nowox Dec 06 '15 at 20:07
  • Gotcha. I incorporated shx2's get() suggestion after I saw his answer. I thought you were after some way to manage all the 'do somethings'. – Tom Barron Dec 06 '15 at 20:09
1

The way to check for a value that might not be set is with get(), which returns None on missing keys instead of raising an error. But you should also change the is True part:

  1. A boolean test comes out true if you just check the value itself; so it's simpler (and proper python style) to write

    if kwargs.get("foo"): ...

  2. is True is not only redundant, but incorrect: is does not check for value equality, but for identity. Any non-zero value counts as true in python, but e.g. 1 is True comes out as false! 1 == True checks for "truthiness", and is what you should have used (if anything). Even if this function will only receive True booleans, it's a bad idea to burden your code with needlessly strong assumptions about what it will see.

alexis
  • 48,685
  • 16
  • 101
  • 161
  • what if you are explicitly looking for `True`? `if kwargs.get('foo')` is not the same as `if kwargs.get('foo') is True`. Saying it is wrong is like saying `if some_val is None` is wrong – Padraic Cunningham Dec 06 '15 at 20:19
  • In that case, `is True` is indeed appropriate. What do you think are the odds of that in this case? – alexis Dec 06 '15 at 20:21
  • Re the edit to your comment: I called it incorrect precisely because it is not the same. – alexis Dec 06 '15 at 20:22
  • it is all about context, only the OP knows what values are possible – Padraic Cunningham Dec 06 '15 at 20:23
  • I agree, only the OP knows. But the `None` case is not the same: `None` is "falsy" but is also a missing value, so checking against it reveals a specific intent. If someone was testing with `is False`, then I would have made the same warning. Yes, it's conceivable but unlikely that it is really intended. – alexis Dec 06 '15 at 20:25
  • I meant that sometimes you do want to check if something `is True`, we cannot say something is wrong without first knowing the context of how it is being used – Padraic Cunningham Dec 06 '15 at 20:54
  • @Padraic, I agree as far as that goes. But I'm pretty confident in my guess at the author's intent, and in _that_ context, "`is True`" is incorrect. – alexis Dec 07 '15 at 09:34