Добавляйте только к dict, если выполняется условие
Я использую urllib.urlencode
для создания параметров веб-POST, но есть несколько значений, которые я хочу добавить только в том случае, если для них существует значение, отличное от None
.
apple = 'green'
orange = 'orange'
params = urllib.urlencode({
'apple': apple,
'orange': orange
})
Это работает отлично, однако, если я делаю необязательной переменную orange
, как я могу предотвратить ее добавление к параметрам? Что-то вроде этого (псевдокод):
apple = 'green'
orange = None
params = urllib.urlencode({
'apple': apple,
if orange: 'orange': orange
})
Надеюсь, это было достаточно ясно, кто-нибудь знает, как это решить?
Ответы
Ответ 1
Вам нужно будет добавить ключ отдельно, после создания начального dict
:
params = {'apple': apple}
if orange is not None:
params['orange'] = orange
params = urllib.urlencode(params)
Python не имеет синтаксиса для определения ключа как условного; вы могли бы использовать понимание dict, если у вас уже было все в последовательности:
params = urllib.urlencode({k: v for k, v in (('orange', orange), ('apple', apple)) if v is not None})
но это не очень читаемо.
Ответ 2
Чтобы получить ответ на sqreept, вот подкласс dict
, который ведет себя по желанию:
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
Это позволит изменить значения существующих ключей на None
, но присваивание None
к ключу, который не существует, является no-op. Если вы хотите установить элемент None
, чтобы удалить его из словаря, если он уже существует, вы можете сделать это:
def __setitem__(self, key, value):
if value is None:
if key in self:
del self[key]
else:
dict.__setitem__(self, key, value)
Значения None
могут войти, если вы передадите их во время строительства. Если вы хотите этого избежать, добавьте метод __init__
для их фильтрации:
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
Вы также можете сделать его общим, написав его, чтобы при создании словаря вы могли перейти в желаемое условие:
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
Довольно старый вопрос, но вот альтернатива, использующая тот факт, что обновление dict с помощью пустого dict ничего не делает.
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
Вы можете очистить None после назначения:
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
Еще один правильный ответ заключается в том, что вы можете создать свой собственный диктоподобный контейнер, который не сохраняет значения None.
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
дает:
{'orange': 'orange'}
Ответ 6
Я сделал это. Надеюсь, это поможет.
apple = 23
orange = 10
a = {
'apple' : apple,
'orange' if orange else None : orange if orange else None
}
Ожидаемый результат: {'orange': 10, 'apple': 23}
Хотя, если orange = None
, тогда будет одна запись для None:None
. Например, рассмотрим это:
apple = 23
orange = None
a = {
'apple' : apple,
'orange' if orange else None : orange if orange else None
}
Ожидаемый результат: {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 })