首页 > 解决方案 > Python 不能在列表推导中使用三元运算符解包

问题描述

假设我有一本字典

kwargs = {'key1': 1, 
          'key2': 2,
          'key3list': [1,2,3,4]}

其中任何键的值之一可以是整数列表,而其他键的值可以是任何对象,在这种情况下,是整数。我想在一行(或最多几行)中,将键的所有值放入一个元组中,解压缩所有可能的列表。请注意,根据字典kwargs的构造方式,具有列表的键将具有以“列表”结尾的键。

我想出了以下内容:

a = tuple(
[kwargs[key] if not key.endswith('list') else *kwargs[key] for key in kwargs.keys()]
)

但是我得到了我无法*kwargs[key]在这里解压的错误..

我该如何解决这个问题?

标签: pythonlisttupleslist-comprehensionternary-operator

解决方案


可以使用嵌套列表组合来完成,但它并不漂亮。一种方法是将非列表项包装到列表中,然后解压缩生成的 2D 列表。

kwargs = {
    'key1': 1,
    'key2': 2,
    'key3list': [1, 2, 3, 4],
}

a = [u for v in 
        [val if key.endswith('list') else [val] for key, val in kwargs.items()] 
    for u in v]
print(a)

输出

[1, 2, 1, 2, 3, 4]

强烈建议在这里使用传统的循环技术,不要尝试在列表组合中完成所有操作。例如,

a = []
for key, val in kwargs.items():
    if key.endswith('list'):
        a.extend(val)
    else:
        a.append(val)

print(a)

上面的代码可以写成

a = []
for key, val in kwargs.items():
    meth = a.extend if key.endswith('list') else a.append
    meth(val)

但即使这样也有点太“聪明”了,而且比以前的版本可读性差。


我们可以通过忽略键并测试当前对象是否为列表来使代码更通用:

a = []
for val in kwargs.values():
    if isinstance(val, list):
        a.extend(val)
    else:
        a.append(val)

正如 Lutz Horn 所指出的,如果输出列表的顺序很重要,这种解包策略有点危险,因为传统上在 Python 中,普通的 dict 不一定保留插入顺序。但是在 Python 3.6+ 中,dicts确实保留了顺序,所以这种技术是安全的,但它仍然让我有点不舒服。;)


推荐阅读