Python3.5元组理解真的受到限制吗?

时间:2018-08-26 12:49:38

标签: python python-3.x tuples

我一直喜欢添加到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方式是什么,以与列表和字典理解相同的方式使用?

2 个答案:

答案 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)}

请注意,列表和字典推导也可以类似地工作-它们实际上就像将生成器表达式传递给listsetdict一样。它们主要用来避免在全局名称空间中查找listsetdict


  

我觉得这是一个更多的问题,因为在某些情况下,理解力对于表现至关重要。

在幕后,生成器表达式和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中很昂贵