我一直喜欢添加到Python3.5中的元组理解:
get_query_results
但是,当我尝试直接In [128]: *(x for x in range(5)),
Out[128]: (0, 1, 2, 3, 4)
进行元组理解时,会出现错误:
return
这只是一个小麻烦,因为我可以简单地将元组理解分配给一个变量并返回该变量。但是,如果我尝试将元组理解放入字典理解中,则会出现相同的错误:
In [133]: def testFunc():
...: return *(x for x in range(5)),
...:
File "<ipython-input-133-e6dd0ba638b7>", line 2
return *(x for x in range(5)),
^
SyntaxError: invalid syntax
我觉得这有点问题,因为在某些情况下理解对于表现很重要。
在这些情况下,我对使用字典和列表理解没有任何疑问。在其他情况下,元组理解又有多少其他情况不起作用?还是我用错了?
这让我想知道如果使用如此有限还是我做错了什么呢?如果我没有做错什么,那么创建元组的通用性最快的/最Python方式是什么,以与列表和字典理解相同的方式使用?
答案 0 :(得分:8)
TLDR:如果要使用元组,请将生成器表达式传递给tuple
:
{idx: tuple(x for x in range(5)) for idx in range(5)}
Python中没有“元组理解”。这个:
x for x in range(5)
是一个生成器表达式。在其周围添加括号仅用于将其与其他元素分开。这与(a + b) * c
中的相同,后者也不涉及元组。
*
符号用于 iterator 包装/拆包。生成器表达式恰好是可迭代的,因此可以解压缩。但是,必须有一些东西可以将可迭代的打包为。例如,还可以将列表解压缩到作业的元素中:
*[1, 2] # illegal - nothing to unpack into
a, b, c, d = *[1, 2], 3, 4 # legal - unpack into assignment tuple
现在,执行*<iterable>,
将*
的拆包与,
元组文字组合在一起。不过,这不是在所有情况下都可用的-分隔元素可能优先于创建元组。例如,,
中的最后一个[*(1, 2), 3]
分开,而在[(*(1, 2), 3)]
中,它创建一个元组。
在字典中,,
含糊不清,因为它用于分隔元素。比较{1: 1, 2: 2}
并注意{1: 2,3}
是非法的。对于return
语句,它为might be possible in the future。
如果要使用元组,则应在可能出现歧义的情况下使用()
-即使Python可以处理它,否则很难为人类解析。
当您的源代码是一个大型语句(例如生成器表达式)时,建议您显式转换为元组。比较代码的以下两个 valid 版本以提高可读性:
{idx: tuple(x for x in range(5)) for idx in range(5)}
{idx: (*(x for x in range(5)),) for idx in range(5)}
请注意,列表和字典推导也可以类似地工作-它们实际上就像将生成器表达式传递给list
,set
或dict
一样。它们主要用来避免在全局名称空间中查找list
,set
或dict
。
我觉得这是一个更多的问题,因为在某些情况下,理解力对于表现至关重要。
在幕后,生成器表达式和list / dict / set理解都创建了一个短暂的函数。除非已对它们进行了概要分析和测试,否则您不应依赖于理解来进行性能优化。默认情况下,请使用您的用例中最易读的内容。
dis.dis("""[a for a in (1, 2, 3)]""")
1 0 LOAD_CONST 0 (<code object <listcomp> at 0x10f730ed0, file "<dis>", line 1>)
2 LOAD_CONST 1 ('<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_CONST 5 ((1, 2, 3))
8 GET_ITER
10 CALL_FUNCTION 1
12 RETURN_VALUE
答案 1 :(得分:1)
从there are no tuple-comprehensions开始,将生成器表达式传递到tuple()
构造函数中:
{idx: tuple(x for x in range(5)) for idx in range(5)}
元组理解不存在,但是即使列表理解存在([... for ... in ...]
),它们也类似于*:list(... for ... in ...)
。
*列表推导实际上比传递到构造函数的生成器表达式要快,因为执行函数在Python中很昂贵