Only add to a dict if a condition is met

孤人 提交于 2019-11-27 19:35:13

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

params = {'apple': apple}
if orange is not None:
    params['orange'] = orange
params = 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.

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"] = None
assert "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 key
assert "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)
params = urllib.urlencode({
    'apple': apple,
    **({'orange': orange} if orange else {}),
})

You can clear None after the assignment:

apple = 'green'
orange = None
dictparams = {
    'apple': apple,
    'orange': orange
}
for k in dictparams.keys():
    if not dictparams[k]:
        del dictparams[k]
params = urllib.urlencode(dictparams)

Another valid answer is that you can create you own dict-like container that doesn't store None values.

class MyDict:
    def __init__(self):
        self.container = {}
    def __getitem__(self, key):
        return self.container[key]
    def __setitem__(self, key, value):
        if value != None:
            self.container[key] = value
    def __repr__(self):
        return self.container.__repr__()

a = MyDict()
a['orange'] = 'orange';
a['lemon'] = None

print a

yields:

{'orange': 'orange'}

I did this. Hope this help.

apple = 23
orange = 10
a = {
    'apple' : apple,
    'orange' if orange else None : orange if orange else None
}

Expected output : {'orange': 10, 'apple': 23}

Although, if orange = None , then there will be a single entry for None:None. For example consider this :

apple = 23
orange = None
a = {
    'apple' : apple,
    'orange' if orange else None : orange if orange else None
}

Expected Output : {None: None, 'apple': 23}

fruits = [("apple", get_apple()), ("orange", get_orange()), ...]

params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None })

I really like the neat trick in the answer here: https://stackoverflow.com/a/50311983/3124256

But, it has some pitfalls:

  1. Duplicate if tests (repeated for key and value)
  2. Pesky None: None entry in the resulting dict

To avoid this, you can do the following:

apple = 23
orange = None
banana = None
a = {
    'apple' if apple else None: apple,
    'orange' if orange else None : orange,
    'banana' if banana else None: banana,
    None: None,
}
del a[None]

Expected Output : {'apple': 23}

Note: the None: None entry ensures two things:

  1. The None key will always be present (del won't throw an error)
  2. The contents of 'None values' will never exist in the dict (in case you forget to del afterwards)

If you aren't worried about these things, you can leave it out and wrap the del in a try...except (or check if the None key is present before deling). To address number 2 alternatively, you could also put the conditional check on the value (in addition to the key).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!