我正在使用urllib.urlencode
来构建Web 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
})
我希望这很清楚,有谁知道如何解决这个问题?
答案 0 :(得分:41)
在创建初始dict
后,您必须单独添加密钥:
params = {'apple': apple}
if orange is not None:
params['orange'] = orange
params = urllib.urlencode(params)
Python没有将键定义为条件的语法;如果你已经拥有了序列中的所有内容,你可以使用词典理解:
params = urllib.urlencode({k: v for k, v in (('orange', orange), ('apple', apple)) if v is not None})
但那不太可读。
答案 1 :(得分:26)
为了搭载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
分配给不存在的密钥是无操作。如果您希望将项目设置为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
答案 2 :(得分:13)
相当古老的问题,但是这里有一个替代方案,即使用空字典更新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)
答案 3 :(得分:3)
您可以在分配后清除无:
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 :(得分:2)
另一个有效的答案是你可以创建自己的类似dict的容器,它不存储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'}
答案 5 :(得分:1)
params = urllib.urlencode({
'apple': apple,
**({'orange': orange} if orange else {}),
})
答案 6 :(得分:1)
我建议的一种技术是为此使用 dictionary unpacking operatior。
apple = 'green'
orange = None
params = urllib.urlencode({
'apple': apple,
**({ 'orange': orange } if orange else {})
})
基本上,如果orange
是None
,那么上面的字典简化为
{
'apple': apple,
**({})
}
# which results in just
{
'apple': apple,
}
如果 orange
不是 None
,则相反:
{
'apple': apple,
**({ "orange": orange })
}
# which results in just
{
'apple': apple,
'orange': orange
}
可读性是有条件地添加内联键的缺点。可以创建一个有助于调解可读性问题的函数。
from typing import Callable
def cond_pairs(
cond: bool, pairs: Callable[[], dict],
) -> dict:
return pairs() if cond else {}
{
'apple': apple,
**cond_pairs(orange, lambda: { 'orange': orange })
}
答案 7 :(得分:1)
我发现使用 generator function 更容易理解,而且足够灵活。它也适用于 Python 2 和 3。
def generate_request_items(apple, orange):
yield "apple", apple
if orange:
yield "orange", orange
# Add additional conditionals and yield statements here
apple = 'green'
orange = None
params = urllib.urlencode(dict(generate_request_items(apple, orange)))
答案 8 :(得分:0)
fruits = [("apple", get_apple()), ("orange", get_orange()), ...]
params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None })
答案 9 :(得分:0)
我真的很喜欢这里答案中的巧妙技巧:https://stackoverflow.com/a/50311983/3124256
但是,它有一些陷阱:
var qryResults =
(from r in dbContext.Routes
join br in dbContext.BrokerRoutes on r.RouteId equals br.RouteId
where br.Broker.ApiKey == apiKey
join pr in dbContext.RoutePathFilters.Include(x => x.PathFilter) on r.RouteId equals pr.RouteId into paths
group new { r, paths } by r.RouteId into rprg
let r = rprg.First().r
select new RouteTemplate {
RouteId = rprg.Key,
Version = r.Version.Version,
Url = r.Url,
IsActive = r.IsActive,
Paths = rprg.Select(rpr => rpr.paths.First().PathFilter.FilterName).ToList()
})
.AsNoTracking()
.ToImmutableList();
个测试(重复键和值)if
中的None: None
条目为避免这种情况,您可以执行以下操作:
dict
预期输出: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]
注意:{'apple': 23}
条目可确保两件事:
None: None
键将始终存在(None
不会引发错误)del
)如果您不担心这些事情,可以将其忽略,然后将del包裹在del
中(或检查try...except
之前是否存在None
键) 。要解决2号问题,您还可以对值(除了键)进行条件检查。
答案 10 :(得分:0)
有一个违反直觉但可靠的技巧,可以重用您要排除的其他道具名称。
{
'orange' if orange else 'apple': orange,
'apple': apple,
}
在这种情况下,后一个“苹果”将覆盖前一个“苹果”,从而有效地将其删除。请注意,条件表达式应高于真实表达式。
答案 11 :(得分:0)
通过字典理解,您可以使用一个条件处理所有可选项目:
apple = "red"
orange = None
dictparams = {
key: value for key, value in
{
"apple": apple,
"orange": orange
}.items()
if value is not None
}
在这种情况下,dictparams
结果将不包含"orange"
,因为orange
是None
:
{'apple': 'green'}