Python3.5元组理解真的如此有限吗?

Python3.5元组理解真的如此有限吗?,python,python-3.x,tuples,Python,Python 3.x,Tuples,我一直喜欢Python3.5中添加的元组理解: In [128]: *(x for x in range(5)), Out[128]: (0, 1, 2, 3, 4) 然而,当我试图直接返回元组理解时,我得到一个错误: In [133]: def testFunc(): ...: return *(x for x in range(5)), ...: File "<ipython-input-133-e6dd0ba638b7>", line 2

我一直喜欢Python3.5中添加的元组理解:

In [128]: *(x for x in range(5)),
Out[128]: (0, 1, 2, 3, 4)
然而,当我试图直接返回元组理解时,我得到一个错误:

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    
[133]中的
:def testFunc():
…:返回*(范围(5)中的x代表x),
...: 
文件“”,第2行
返回*(范围(5)内的x对应x),
^
SyntaxError:无效语法
这只是一个小小的不便,因为我可以简单地将元组理解分配给变量并返回变量。但是,如果我尝试将元组理解放在字典理解中,我会得到相同的错误:

In [130]: {idx: *(x for x in range(5)), for idx in range(5)}
  File "<ipython-input-130-3e9a3eee879c>", line 1
    {idx: *(x for x in range(5)), for idx in range(5)}
          ^
SyntaxError: invalid syntax
In[130]:{idx:*(x表示范围(5)中的x),表示范围(5)中的idx}
文件“”,第1行
{idx:*(x表示范围(5)中的x),表示范围(5)中的idx}
^
SyntaxError:无效语法
我觉得这是一个更大的问题,因为压缩在某些情况下对性能很重要

在这种情况下,我使用字典和列表理解没有问题。还有多少情况是元组理解在其他情况下不起作用?或者我用错了


这让我想知道,如果它的用途如此有限,或者我做错了什么,那重点是什么?如果我没有做错什么,那么创建元组的最快/最具python风格的方法是什么,该元组的版本足以与列表和字典理解相同?

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中的相同,也不涉及元组

*
符号用于迭代器打包/解包。生成器表达式恰好是iterable,因此可以将其解包。但是,必须有一些东西可以打开iterable。例如,还可以将列表解包到分配的元素中:

*[1, 2]                         # illegal - nothing to unpack into
a, b, c, d = *[1, 2], 3, 4      # legal - unpack into assignment tuple
现在,执行
*,
*
解包与
元组文字相结合。这并不是在所有情况下都可以使用的,但是-分隔元素可能优先于创建元组。例如,在
[*(1,2),3]
中,最后一个
是分开的,而在
[(*(1,2,3)]
中,它创建了一个元组

在字典中,
是不明确的,因为它用于分隔元素。比较
{1:1,2:2}
,注意
{1:2,3}
是非法的。对于
return
语句,它是

如果您想要一个元组,那么应该在可能存在歧义的时候使用
()
——即使Python可以处理它,否则很难为人类解析

如果源代码是大型语句(如生成器表达式),我建议显式转换为元组。比较代码的以下两个有效版本的可读性:

{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)}
请注意,列表和dict理解的工作原理也类似-它们实际上类似于将生成器表达式传递给
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
dis.dis(“[a代表(1,2,3)]”)
1 0加载常数0(<0x10f730ed0处的代码对象列表,文件“dis”,第1行>)
2荷载常数1(“”)
4生成函数0
6荷载常数5((1、2、3))
8获得
10调用函数1
12返回值

将生成器表达式传递到
tuple()构造函数中,因为:


元组理解不存在,但即使列表理解存在(
[…for…in…][/code>),它们也类似于*:
列表(…for…in…



*列表理解实际上比传递到构造函数中的生成器表达式要快,因为在Python中执行函数很昂贵

这不是元组理解,而是生成器表达式。
*
不是生成器表达式的一部分!它是解包的符号。您可以添加括号:
return(*(…),)
,但您更应该使用
tuple(…)
。明确考虑并拒绝在理解中使用星号解包:有关详细信息,请参阅。然而,
return
中的无效语法让我吃惊;有可能这只是一个疏忽。“返回语句和字典值都不适用于此。”@jpp是的,反汇编显示了
MAKE\u函数
。列表理解会消耗中间生成器,因此您永远无法访问它。@jpp正确的是,它不是理解的生成器函数,而是函数。抽象是有漏洞的,函数可以转换为生成器函数:注意,我并不是说列表理解比生成器表达式+列表慢。不过,它们可能比其他方法慢。使用
a=[];a、 extend(map(func,range(10000))
在我的测试中比
[func(i)for i in range(10000)]
快。@MisterMiyagi:是的,但是我看不出有什么好的理由使
返回*(1,2),3
非法,这对
x=*(1,2),3
(这是合法的)。返回的
中没有歧义,至少
{idx: tuple(x for x in range(5)) for idx in range(5)}