是否可以在dict文字中使用可选键?

Jam*_*rgy 0 python dictionary dictionary-comprehension

是否可以在dict文字中使用"可选"键,而不是将它们添加到if语句中?

像这样:

a = True
b = False
c = True
d = False

obj = {
    "do_a": "args for a" if a,
    "do_b": "args for b" if b,
    "do_c": "args for c" if c,
    "do_d": "args for d" if d,
}

#expect:
obj == {
    "do_a": "args for a",
    "do_c": "args for c",
}
Run Code Online (Sandbox Code Playgroud)

编辑上下文:我知道如何做逻辑:)我只是想避免if语句,因为我的对象是一个代表声明性逻辑的大块数据,所以移动的东西有点像"意大利面条编码"的东西不是根本就是程序性的.我希望对象的值"看起来像它意味着什么"作为查询.

它实际上是一个弹性搜索查询,所以它看起来像这样:

{
    "query": {
        "bool": {
            "must": [
                 <FILTER A>,
                 <FILTER B>,  # would like to make this filter optional
                 <FILTER C>,
                 {
                     "more nested stuff" : [ ... ]
                 }
             ],
             "other options": [ ... ]
        },
        "other options": [ ... ]
    },
    "other options": [ ... ]
}
Run Code Online (Sandbox Code Playgroud)

而我可疑的目标是让它看起来像一个你可以看到并理解它的形状的查询,而不必追踪ifs.即,没有"过滤器":[f f in filter in f.enabled]因为那时你必须去寻找过滤器,这些都是可选的常量

cs9*_*s95 5

首先定义键,参数和布尔变量列表:

keys = ["do_a", "do_b", ...]
args = ["args for a", "args for b", ...]
mask = [a, b, ...]
Run Code Online (Sandbox Code Playgroud)

现在,obj使用mask列表构造以确定插入了哪些键:

obj = {k : a for k, a, m in zip(keys, args, mask) if m}
Run Code Online (Sandbox Code Playgroud)

或者,

obj = {}
for k, a, m in zip(keys, args, mask):
    if m:
        obj[k] = a
Run Code Online (Sandbox Code Playgroud)


MSe*_*ert 5

不,你不能在文字中有"可选值".文字中表达式的结果总是插入到结果中.

但是,我认为if无论如何都可能更好地遵循明确的陈述:

a = True
b = False
c = True
d = False

obj = {}
if a: obj["do_a"] = "args for a"
if b: obj["do_b"] = "args for b"
if c: obj["do_c"] = "args for c"
if d: obj["do_d"] = "args for d"
Run Code Online (Sandbox Code Playgroud)

如果您真的不喜欢ifs ,请提几个选择:

  • 如果参数为"false"-ey,您还可以使用不同的值,然后过滤字典:

    _to_remove = object()
    
    obj = {
        "do_a": "args for a" if a else _to_remove,
        "do_b": "args for b" if b else _to_remove,
        "do_c": "args for c" if c else _to_remove,
        "do_d": "args for d" if d else _to_remove,
    }
    
    obj = {key: value for key, value in obj.items() if value is not _to_remove}
    
    Run Code Online (Sandbox Code Playgroud)
  • 或使用itertools.compress和dict内置:

    key_value_pairs = [
        ("do_a", "args for a"), 
        ("do_b", "args for b"), 
        ("do_c", "args for c"), 
        ("do_d", "args for d")
    ]
    
    from itertools import compress
    
    obj = dict(compress(key_value_pairs, [a, b, c, d]))
    
    Run Code Online (Sandbox Code Playgroud)


Jam*_*rgy 5

我认为答案是否定的,正如其他答案所述,但这是我迄今为止最接近的......

不过,它在 'wtf' 的'可恶' 方面稍微有点

a = True
b = False
c = True
d = False

obj = {
    **({"do_a": "args for a"} if a else {}),
    **({"do_b": "args for b"} if b else {}),
    **({"do_c": "args for c"} if c else {}),
    **({"do_d": "args for d"} if d else {}),
}

#expect:
assert(obj == {
        "do_a": "args for a",
        "do_c": "args for c",
    })
Run Code Online (Sandbox Code Playgroud)

或者如果你想把可选性放在某个函数中:

def maybe(dictionary, condition, default=None):
    return dictionary if condition else default or {}

obj = {
    **maybe({"do_a": "args for a"}, a),
    **maybe({"do_b": "args for b"}, b),
    **maybe({"do_c": "args for c"}, c),
    **maybe({"do_d": "args for d"}, d),
}
Run Code Online (Sandbox Code Playgroud)

这种代码的问题是条件离结果越来越远(想象一下,我们最终将大字典传递给 中的第一个参数maybe)。