2
def foo(l=None, d=None):
    return bar(*l, **d) # eg. bar(1, 2, 3, a=a, b=b)

Input:

l = [1, 2, 3]
d = {'a': a, 'b': b}

foo(l=l, d=d)

Problem arises when l is None, ie. this call is made:

foo(d={'a':a})

What do I change in foo to handle NoneType on both the list and the dict nicely?

This is ugly, there has to be a better way than this:

def foo(l=None, d=None):
    if l is not None and d is not None:
        return bar(*l, **d)
    if l is not None:
        return bar(*l)
    if d is not None:
        return bar(**d)
emihir0
  • 1,200
  • 3
  • 16
  • 39
  • The *better* way would be not to have a wrapper function `foo` that exposes just a list and a dictionary argument. If you have variable/keyword arguments, just expose that in the function signature, so users know they can use it. – poke Aug 07 '17 at 11:38
  • `if l is not None and d is not None:` is ugly, use `if l and d:` – Mohd Aug 07 '17 at 11:38

3 Answers3

4

You can short-circuit with empty iterables using or:

def foo(l=None, d=None):
    return bar(*(l or ()), **(d or {}))

Or make it more readable, albeit more verbose with:

def foo(l=None, d=None):
    l = l or ()
    d = d or {}
    return bar(*l, **d)
Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
2

Use an empty tuple and an empty dictionary as default arguments instead of None:

def foo(l=(), d={}):
    return bar(*l, **d)

You have to be careful not to change d inside the foo function because it's a mutable default argument (see also "Least Astonishment" and the Mutable Default Argument). If you want to be cautious you could use an immutable dictionary:

from types import MappingProxyType  # requires python 3.3

def foo(l=(), d=MappingProxyType({})):
    return bar(*l, **d)
MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • Why a tuple though? Why not an empty list for `l`? – stelioslogothetis Aug 07 '17 at 11:35
  • 3
    Not sure about `d = {}`, since dicts are mutable. – Moses Koledoye Aug 07 '17 at 11:35
  • @MosesKoledoye If the only purpose of the function is unpacking the dict then there's nothing that can change the dict. – MSeifert Aug 07 '17 at 11:36
  • 1
    Be very careful with such things though. it works here, since the list and dict are immediately unpacked, but it is very dangerous in general to have mutable defaults: [“Least Astonishment” and the Mutable Default Argument](https://stackoverflow.com/q/1132941/216074) – poke Aug 07 '17 at 11:36
  • I select @MosesKoledoye's answer because as others have said, `{}` is mutable and so I prefer the `None` being default style. – emihir0 Aug 07 '17 at 11:43
  • That's your call. In your case it doesn't matter if it's mutable or not and even if it would matter just use an read-only dictionary. – MSeifert Aug 07 '17 at 11:49
-1

Kindly check, Will this help you..

def bar(*mylist, **mydict):
    print mylist
    print mydict


def foo(arg=None, kwarg=None):
    if not isinstance(arg, list):
        arg = []
    if not isinstance(kwarg, dict):
        kwarg = {}
    return bar(*arg, **kwarg)


l = [1, 2, 3]
d  ={'a': 'a', 'b': 'b'}

foo(l,d)
foo(l, None)
foo(None,d)

output:

(1, 2, 3)
{'a': 'a', 'b': 'b'}

(1, 2, 3)
{}

()
{'a': 'a', 'b': 'b'}
Vineesh
  • 253
  • 2
  • 7