Only add to a dict if a condition is met Only add to a dict if a condition is met python python

Only add to a dict if a condition is met


You'll have to add the key separately, after the creating the initial dict:

params = {'apple': apple}if orange is not None:    params['orange'] = orangeparams = urllib.urlencode(params)

Python has no syntax to define a key as conditional; you could use a dict comprehension if you already had everything in a sequence:

params = urllib.urlencode({k: v for k, v in (('orange', orange), ('apple', apple)) if v is not None})

but that's not very readable.

If you are using Python 3.9 or newer, you could use the new dict merging operator support and a conditional expression:

params = urllib.urlencode(    {'apple': apple} |     ({'orange': orange} if orange is not None else {}))

but I find readability suffers, and so would probably still use a separate if expression:

params = {'apple': apple}if orange is not None:    params |= {'orange': orange}params = urllib.urlencode(params)

Another option is to use dictionary unpacking, but for a single key that's not all that more readable:

params = urllib.urlencode({    'apple': apple,    **({'orange': orange} if orange is not None else {})})

I personally would never use this, it's too hacky and is not nearly as explicit and clear as using a separate if statement. As the Zen of Python states: Readability counts.


To piggyback on sqreept's answer, here's a subclass of dict that behaves as desired:

class DictNoNone(dict):    def __setitem__(self, key, value):        if key in self or value is not None:            dict.__setitem__(self, key, value)d = DictNoNone()d["foo"] = Noneassert "foo" not in d

This will allow values of existing keys to be changed to None, but assigning None to a key that does not exist is a no-op. If you wanted setting an item to None to remove it from the dictionary if it already exists, you could do this:

def __setitem__(self, key, value):    if value is None:        if key in self:            del self[key]    else:        dict.__setitem__(self, key, value)

Values of None can get in if you pass them in during construction. If you want to avoid that, add an __init__ method to filter them out:

def __init__(self, iterable=(), **kwargs):    for k, v in iterable:        if v is not None: self[k] = v    for k, v in kwargs.iteritems():        if v is not None: self[k] = v

You could also make it generic by writing it so you can pass in the desired condition when creating the dictionary:

class DictConditional(dict):    def __init__(self, cond=lambda x: x is not None):        self.cond = cond    def __setitem__(self, key, value):        if key in self or self.cond(value):            dict.__setitem__(self, key, value)d = DictConditional(lambda x: x != 0)d["foo"] = 0   # should not create keyassert "foo" not in d


Pretty old question but here is an alternative using the fact that updating a dict with an empty dict does nothing.

def urlencode_func(apple, orange=None):    kwargs = locals().items()    params = dict()    for key, value in kwargs:        params.update({} if value is None else {key: value})    return urllib.urlencode(params)