Only add to a dict if a condition is met

2019-01-14 05:04发布

I am using urllib.urlencode to build web POST parameters, however there are a few values I only want to be added if a value other than None exists for them.

apple = 'green'
orange = 'orange'
params = urllib.urlencode({
    'apple': apple,
    'orange': orange
})

That works fine, however if I make the orange variable optional, how can I prevent it from being added to the parameters? Something like this (pseudocode):

apple = 'green'
orange = None
params = urllib.urlencode({
    'apple': apple,
    if orange: 'orange': orange
})

I hope this was clear enough, does anyone know how to solve this?

7条回答
成全新的幸福
2楼-- · 2019-01-14 05:51

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
查看更多
Luminary・发光体
3楼-- · 2019-01-14 05:51

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)
查看更多
该账号已被封号
4楼-- · 2019-01-14 05:52

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)
查看更多
再贱就再见
5楼-- · 2019-01-14 05:59

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'}
查看更多
Rolldiameter
6楼-- · 2019-01-14 06:05

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.

查看更多
成全新的幸福
7楼-- · 2019-01-14 06:10

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,
    None : None
}

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

查看更多
登录 后发表回答