Python 仅在满足条件时才添加到 dict

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14263872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 10:55:13  来源:igfitidea点击:

Only add to a dict if a condition is met

pythonvariablesdictionaryurllib

提问by user1814016

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

我正在使用urllib.urlencode构建 web POST 参数,但是有一些值我只想添加,如果None它们不存在其他值。

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

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

这工作正常,但是如果我将orange变量设为可选,如何防止它被添加到参数中?像这样(伪代码):

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?

我希望这已经足够清楚了,有谁知道如何解决这个问题?

采纳答案by Martijn Pieters

You'll have to add the key separately, after the creating the initial dict:

在创建初始后,您必须单独添加密钥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:

Python 没有将键定义为条件的语法;如果您已经将所有内容按顺序排列,则可以使用 dict 理解:

params = urllib.urlencode({k: v for k, v in (('orange', orange), ('apple', apple)) if v is not None})

but that's not very readable.

但这不是很可读。

Another option is to use dictionary unpacking, but for a single key that's not all that more readable:

另一种选择是使用字典 unpacking,但对于单个键,并不是那么可读:

params = urllib.urlencode({
    'apple': apple,
    **({'orange': orange} if orange is not None else {})
})

I personally would never use this, it's too hacky and is not nearly as explicit and clearas using a separate ifstatement. As the Zen of Pythonstates: Readability counts.

我个人永远不会使用这个,它太老套了,不像使用单独的语句那样明确和清晰if。正如Python所说:可读性很重要。

回答by sqreept

You can clear None after the assignment:

您可以在分配后清除 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)

回答by XORcist

fruits = [("apple", get_apple()), ("orange", get_orange()), ...]

params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None })

回答by sqreept

Another valid answer is that you can create you own dict-like container that doesn't store None values.

另一个有效的答案是,您可以创建自己的类似 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

yields:

产量:

{'orange': 'orange'}

回答by kindall

To piggyback on sqreept's answer, here's a subclass of dictthat behaves as desired:

要搭载 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

This will allow values of existing keys to be changedto None, but assigning Noneto a key that does not exist is a no-op. If you wanted setting an item to Noneto removeit from the dictionary if it already exists, you could do this:

这将允许将现有键的值更改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)

Values of Nonecanget in if you pass them in during construction. If you want to avoid that, add an __init__method to filter them out:

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

You could also make it generic by writing it so you can pass inthe 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

回答by lindsay.stevens.au

Pretty old question but here is an alternative using the fact that updating a dict with an empty dict does nothing.

很老的问题,但这里有一个替代方案,即使用空 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)

回答by Nikhil Wagh

I did this. Hope this help.

我这样做了。希望这有帮助。

apple = 23
orange = 10
a = {
    'apple' : apple,
    'orange' if orange else None : orange
}

Expected output : {'orange': 10, 'apple': 23}

预期输出: {'orange': 10, 'apple': 23}

Although, if orange = None, then there will be a single entry for None:None. For example consider this :

虽然,如果orange = None,那么 将有一个条目None:None。例如考虑这个:

apple = 23
orange = None
a = {
    'apple' : apple,
    'orange' if orange else None : orange
}

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

预期输出: {None: None, 'apple': 23}

回答by DylanYoung

I really like the neat trick in the answer here: https://stackoverflow.com/a/50311983/3124256

我真的很喜欢这里答案中的巧妙技巧:https: //stackoverflow.com/a/50311983/3124256

But, it has some pitfalls:

但是,它有一些陷阱:

  1. Duplicate iftests (repeated for key and value)
  2. Pesky None: Noneentry in the resulting dict
  1. 重复if测试(对键和值重复)
  2. 结果中的讨厌None: None条目dict

To avoid this, you can do the following:

为避免这种情况,您可以执行以下操作:

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]

Expected Output : {'apple': 23}

预期输出: {'apple': 23}

Note: the None: Noneentry ensures two things:

注意:该None: None条目确保两件事:

  1. The Nonekey will always be present (delwon't throw an error)
  2. The contents of 'None values' will never exist in the dict (in case you forget to delafterwards)
  1. None键将始终存在(del会不会引发错误)
  2. 字典中永远不会存在“无值”的内容(以防您del之后忘记)

If you aren't worried about these things, you can leave it out and wrap the del in a try...except(or check if the Nonekey is present before deling). To address number 2 alternatively, you could also put the conditional check on the value (in addition to the key).

如果您不担心这些事情,您可以将其省略并将 del 包裹在 a 中try...except(或Nonedeling之前检查密钥是否存在)。或者,要解决数字 2,您还可以对值进行条件检查(除了键之外)。

回答by Данила Фомин

params = urllib.urlencode({
    'apple': apple,
    **({'orange': orange} if orange else {}),
})

回答by Ilya Kharlamov

There is a counter-intuitive but reliable hack, to reuse the other prop name you want to exclude it.

有一个违反直觉但可靠的技巧,可以重用您想要排除的其他道具名称。

{
    'orange' if orange else 'apple': orange,
    'apple': apple,
}

In this case, the latter 'apple' will override the previous 'apple' effectively removing it. Note that the conditional expressions should go above the real ones.

在这种情况下,后一个“苹果”将覆盖前一个“苹果”,有效地将其删除。请注意,条件表达式应高于真实表达式。