是否可以在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",
}
根据上下文编辑:
我知道该怎么做:)我只想避免使用if
语句,因为我的对象是代表声明性逻辑的大数据块,因此移动内容有点像“意大利面条式编码”,是“它根本就意味着程序性。
我希望对象的值“看起来像是什么意思”作为查询。
这实际上是一个Elasticsearch查询,因此看起来像这样:
{
"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": [ ... ]
}
我可能会怀疑的目标是使它看起来像一个查询,您可以查看它并了解它的形状,而不必通过if
进行跟踪。
即,没有“过滤器”:[f表示过滤器中的f,如果启用f。
因为然后您必须去寻找过滤器,这些过滤器在这里都是可选的常量
答案 0 :(得分:5)
首先定义键,参数和布尔变量的列表:
keys = ["do_a", "do_b", ...]
args = ["args for a", "args for b", ...]
mask = [a, b, ...]
现在,使用obj
列表构造mask
以确定要插入的键:
obj = {k : a for k, a, m in zip(keys, args, mask) if m}
或者,
obj = {}
for k, a, m in zip(keys, args, mask):
if m:
obj[k] = a
答案 1 :(得分: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"
在您真的不喜欢if
的情况下,只需提及一些替代方法:
如果参数为“ 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}
或使用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]))
答案 2 :(得分:1)
这是另一种方法。给定与您相同的定义:
a = True
b = False
c = True
d = False
然后,您可以将文字构造为三个成员元组:
li=[
("do_a", "args for a",a),
("do_b", "args for b",b),
("do_c", "args for c",c),
("do_d", "args for d",d)
]
这等效于将zip
与三个文字列表一起使用,但人眼可能会更容易理解较短的列表。
然后有条件地构造您的字典:
>>> dict([(k,v) for k,v,f in li if f])
{'do_c': 'args for c', 'do_a': 'args for a'}
在帖子中已作了澄清,您可以将函数用作dict值,并在创建dict(或更新dict)时简单地调用该函数:
def filter_a():
# some expensive function...
return "<FILTER A>"
def filter_b():
return "<FILTER B>"
def filter_c():
return "<FILTER C>"
def filter_d():
return "<FILTER D>"
li=[
("do_a", filter_a, a),
("do_b", filter_b, b),
("do_c", filter_c, c),
("do_d", filter_d, d)
]
然后仅将相关的过滤器函数按构造方式调用:
>>> dict((k,v()) for k,v,f in li if f)
{'do_c': '<FILTER C>', 'do_a': '<FILTER A>'}
然后永远不会调用B和D。
更好地编写逻辑,以使FILTER X是一种生成器,并仅在需要时返回数据。
答案 3 :(得分:1)
我认为答案是“否”,正如其他答案所述,但这是我到目前为止得到的最接近的答案...
虽然它略微位于'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",
})
或者如果您想在某些函数中添加可选性:
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),
}
这种代码的问题是条件离结果越来越远(假设我们最终将大的dict传递给maybe
的第一个参数)。