众所周知,Python中有列表推导式,例如
[i for i in [1, 2, 3, 4]]
还有字典推导式,例如
{i:j for i, j in {1: 'a', 2: 'b'}.items()}
但是
(i for i in (1, 2, 3))
将最终结果放在生成器中,而不是tuple
推导式中。为什么呢?
我猜这是因为tuple
是不可变的,但这似乎不是答案。
众所周知,Python中有列表推导式,例如
[i for i in [1, 2, 3, 4]]
还有字典推导式,例如
{i:j for i, j in {1: 'a', 2: 'b'}.items()}
但是
(i for i in (1, 2, 3))
将最终结果放在生成器中,而不是tuple
推导式中。为什么呢?
我猜这是因为tuple
是不可变的,但这似乎不是答案。
tuple(i for i in (1, 2, 3))
但是括号已经被用来表示生成器表达式了。
list(i for i in (1,2,3))
。我真的认为这只是因为没有一个清晰的语法来表示它(或者至少没有人想到过)。 - mgilsonlist(i for i in (1,2,3))
是一个生成器表达式,输出一个列表;set(i for i in (1,2,3))
输出一个集合。这是否意味着不需要推导式的语法呢?也许不是,但它非常方便。对于你需要元组的罕见情况,生成器表达式可以胜任,而且清晰明了,不需要发明另一个括号或方括号。 - Martijn Pieters[thing for thing in things]
构造列表比 list(thing for thing in things)
更快。元组推导式并非毫无用处;tuple(thing for thing in things)
存在延迟问题,而 tuple([thing for thing in things])
可能存在内存问题。 - Justin Turner ArthurPython核心开发人员之一Raymond Hettinger在最近的推文中对元组发表了以下看法:
#python提示:通常,列表用于循环;元组用于结构体。列表是同构的;元组是异构的。列表用于可变长度。
我认为这个观点支持这样一个想法:如果序列中的项目足够相关以至于可以通过生成器生成,那么它应该是一个列表。尽管元组是可迭代的,并且看起来像一个不可变的列表,但它实际上是Python中C结构体的等价物:
struct {
int a;
char b;
float c;
} foo;
struct foo x = { 3, 'g', 5.9 };
在Python中成为
x = (3, 'g', 5.9)
operator.itemgetter
。 - chepnertuple(obj[item] for item in items)
相比,我不认为有太大的优势。在我的情况下,我将其嵌入到列表推导式中,以创建元组记录列表。如果我需要在代码中反复执行此操作,则itemgetter看起来很棒。也许无论如何,itemgetter都更符合惯用法? - daveline_values = tuple(int(x.trim()) for x in line.split(','))
。正如其他人所指出的,这里使用元组构造函数而不是推导式会影响性能,并且解析此类大型数据集是您真正关心性能的情况。 - Tom自 Python 3.5 开始, 您还可以使用星号 *
展开语法来展开生成器表达式:
*(x for x in range(10)),
tuple(list(x for x in range(10)))
相同(代码路径是相同的,两者都创建一个列表,唯一的区别是最后一步是从列表中创建一个元组,并在需要元组输出时丢弃列表)。这意味着你实际上并没有避免使用一对临时变量。 - ShadowRanger*(x for x in range(10))
无法正常工作。我得到了SyntaxError: can't use starred expression here
的错误提示。然而,tuple(x for x in range(10))
可以正常工作。 - Ryan H.正如另一名帖子的macm
在他的回答中提到的那样,从生成器创建元组的最快方法是使用tuple([generator])
。
列表推导:
$ python3 -m timeit "a = [i for i in range(1000)]"
10000 loops, best of 3: 27.4 usec per loop
列表解析生成元组:
$ python3 -m timeit "a = tuple([i for i in range(1000)])"
10000 loops, best of 3: 30.2 usec per loop
从生成器生成元组:
$ python3 -m timeit "a = tuple(i for i in range(1000))"
10000 loops, best of 3: 50.4 usec per loop
通过解包得到元组:
$ python3 -m timeit "a = *(i for i in range(1000)),"
10000 loops, best of 3: 52.7 usec per loop
我的Python版本:
$ python3 --version
Python 3.6.3
因此,除非性能不是问题,否则您应该始终从列表推导式创建元组。
列表推导式
的 元组
需要基于最终 元组
和 列表
的大小来计算峰值内存使用量。而 生成器表达式
的 元组
,虽然比较慢,但意味着您只需支付最终 元组
的费用,没有临时的 列表
(生成器表达式本身占据大致固定的内存)。通常情况下这不重要,但当涉及到的大小特别大时,就可能变得重要。 - ShadowRangertuple([i for i in range(1000)])
在可读性和速度方面是最好的选择。当然,对于更小/更大/不同的数据集,时间可能会有所不同。 - jamylak理解工作是通过循环或迭代遍历项目并将它们分配到一个容器中完成的,元组无法接收分配。
一旦创建了元组,就不能向其附加、扩展或分配。修改元组的唯一方法是如果其中一个对象本身可以被赋值(是非元组容器)。因为元组只持有对该类型对象的引用。
另外,元组有自己的构造函数tuple()
,您可以将任何迭代器传递给它。这意味着要创建一个元组,您可以执行以下操作:
tuple(i for i in (1,2,3))
(1,2,3)
不够简单时,你会怎么做? - Ryan我最好的猜测是他们用完了括号,而且认为添加一个“丑陋”的语法不够有用...
{*()}
虽然丑陋,但作为空集合文字很有效! - user4698348set()
:) - mgilson{*[]}
严格劣于其他选项;空字符串和空元组是不可变的单例,因此构建空集不需要临时变量。相比之下,空列表不是单例,因此你实际上需要构建它,使用它来构建集合,然后销毁它,失去任何微不足道的性能优势。 - ShadowRanger元组无法像列表一样有效地进行追加。
因此,元组推导需要在内部使用列表,然后转换为元组。
这与您现在所做的相同:tuple( [ comprehension ] )
圆括号不会创建一个元组。也就是说,one = (two) 不是一个元组。唯一的解决方法是使用 one = (two,) 或者 one = tuple(two)。因此,一个解决方案如下:
tuple(i for i in myothertupleorlistordict)
one = (two,)
和 one = tuple(two)
的值不同。tuple
函数的参数必须是一个迭代器。one = (two,)
等价于 one = tuple(i for i in two)
,one = tuple((two,))
,以及 one = tuple([two])
。 - markusktuple
推导从未是必要的,可以使用列表代替,速度差异可以忽略,而字典推导与列表推导则不同。tuple(list)
即可。 - mins因为你无法向元组中添加项目。这是如何将简单的列表推导转换为更基本的Python代码。
_list = [1,2,3,4,5]
clist = [ i*i for i in _list ]
print(clist)
clist1 = []
for i in _list:
clist1.append(i*i)
print(clist1)
现在对于上面的示例,使用元组推导意味着将项目添加到不允许的元组中。但是,一旦准备好了,您可以使用tuple(clist1)
将此列表转换为元组。