只有在满足条件时才添加到dict

时间:2013-01-10 17:34:39

标签: python variables dictionary urllib

我正在使用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
})

我希望这很清楚,有谁知道如何解决这个问题?

12 个答案:

答案 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 {})
})

说明

基本上,如果orangeNone,那么上面的字典简化为

{
    '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

但是,它有一些陷阱:

  1. 重复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(); 个测试(重复键和值)
  2. 在结果if中的
  3. 讨厌的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}条目可确保两件事:

  1. None: None键将始终存在(None不会引发错误)
  2. 字典中永远不会存在“无值”的内容(以防以后忘记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",因为orangeNone

{'apple': 'green'}