Python3.5 元组理解真的有这个限制吗? [英] Are Python3.5 tuple comprehension really this limited?

查看:29
本文介绍了Python3.5 元组理解真的有这个限制吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直喜欢添加到 Python3.5 中的元组推导式:

I've been loving the tuple comprehensions added to Python3.5:

In [128]: *(x for x in range(5)),
Out[128]: (0, 1, 2, 3, 4)

然而,当我尝试直接return元组推导式时,我得到一个错误:

However, when I try to return a tuple comprehension directly I get an error:

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    

这只是一个小小的不便,因为我可以简单地将元组推导式分配给一个变量并返回该变量.但是,如果我尝试将元组推导式放入字典推导式中,则会出现相同的错误:

This is just a slight inconvenience since I can simply assign the tuple comprehension to a variable and return the variable. However, if I try and put a tuple comprehension inside a dictionary comprehension I get the same error:

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

我觉得这更像是一个问题,因为在某些情况下,理解对性能很重要.

I feel like this is a bit more of a problem since comprehsions can be important for performance in some situations.

我在这些情况下使用字典和列表推导式没有问题.当其他情况下元组理解不起作用时,还有多少其他情况?还是我用错了?

I have no problem using dictionary and list comprehensions in these situations. How many other situations is the tuple comprehension not going to work when others do? Or perhaps I'm using it wrong?

这让我想知道,如果它的用途如此有限,或者我做错了什么,这有什么意义?如果我没有做错什么,那么创建一个足够通用的元组以与列表和字典推导相同的方式使用的最快/最pythonic 的方法是什么?

It makes me wonder what the point was if it's use is so limited or perhaps I am doing something wrong? If I'm not doing something wrong then what is the fastest/most pythonic way to create a tuple that is versitile enough to be used in the same way as list and dictionary comprehensions?

推荐答案

TLDR:如果你想要一个元组,传递一个生成器表达式给 tuple:

TLDR: If you want a tuple, pass a generator expression to tuple:

{idx: tuple(x for x in range(5)) for idx in range(5)}

<小时>

Python 中没有元组推导式".这:


There are no "tuple comprehensions" in Python. This:

x for x in range(5)

是一个生成器表达式.在它周围添加括号仅用于将其与其他元素分开.这和 (a + b) * c 一样,也不涉及元组.

is a generator expression. Adding parentheses around it is merely used to separate it from other elements. This is the same as in (a + b) * c, which does not involve a tuple either.

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

The * symbol is for iterator packing/unpacking. A generator expression happens to be an iterable, so it can be unpacked. However, there must be something to unpack the iterable into. For example, one can also unpack a list into the elements of an assignment:

*[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)] 它创建了一个元组.

Now, doing *<iterable>, combines * unpacking with a , tuple literal. This is not useable in all situations, though - separating elements may take precedence over creating a tuple. For example, the last , in [*(1, 2), 3] separates, whereas in [(*(1, 2), 3)] it creates a tuple.

在字典中,, 是不明确的,因为它用于分隔元素.比较 {1: 1, 2: 2} 并注意 {1: 2,3} 是非法的.对于 return 语句,它可能在未来实现.

In a dictionary the , is ambiguous since it is used to separate elements. Compare {1: 1, 2: 2} and note that {1: 2,3} is illegal. For a return statement, it might be possible in the future.

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

If you want a tuple, you should use () whenever there might be ambiguity - even if Python can handle it, it is difficult to parse for humans otherwise.

当您的源代码是生成器表达式等大型语句时,我建议显式转换为元组.比较以下两个有效版本的代码以提高可读性:

When your source is a large statement such as a generator expression, I suggest to convert to a tuple explicitly. Compare the following two valid versions of your code for readability:

{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 和 dict 推导式的工作方式也相似——它们实际上就像将生成器表达式传递给 listsetdict.它们主要用于避免在全局命名空间中查找 listsetdict.

Note that list and dict comprehensions also work similar - they are practically like passing a generator expression to list, set or dict. They mostly serve to avoid looking up list, set or dict in the global namespace.

我觉得这更像是一个问题,因为在某些情况下,理解对性能很重要.

I feel like this is a bit more of a problem since comprehsions can be important for performance in some situations.

在幕后,生成器表达式和列表/字典/集合推导式都创建了一个短暂的函数.除非您对它们进行了分析和测试,否则不应依赖于理解来进行性能优化.默认情况下,使用最适合您的用例的任何内容.

Under the covers, both generator expressions and list/dict/set comprehensions create a short-lived function. You should not rely on comprehensions for performance optimisation unless you have profiled and tested them. By default, use whatever is most readable for your use case.

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

这篇关于Python3.5 元组理解真的有这个限制吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆