可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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.
回答2:
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
回答3:
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)
回答4:
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)
回答5:
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'}
回答6:
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}
回答7:
fruits = [("apple", get_apple()), ("orange", get_orange()), ...]
params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None })