简体   繁体   English

在列表中解压缩迭代器的Python方法

[英]Pythonic way to unpack an iterator inside of a list

I'm trying to figure out what is the pythonic way to unpack an iterator inside of a list. 我试图找出在列表中解包迭代器的pythonic方法是什么。

For example: 例如:

my_iterator = zip([1, 2, 3, 4], [1, 2, 3, 4])

I have come with the following ways to unpack my iterator inside of a list: 我提供了以下几种在列表中解压缩迭代器的方法:

1) 1)

my_list = [*my_iterator]

2) 2)

my_list = [e for e in my_iterator]

3) 3)

my_list = list(my_iterator)

No 1) is my favorite way to do it since is less code, but I'm wondering if this is also the pythonic way. No 1)是我最喜欢的方法,因为它减少了代码,但是我想知道这是否也是pythonic方法。 Or maybe there is another way to achieve this besides those 3 which is the pythonic way? 或者,也许除了Python 3之外,还有另一种方法可以实现这一目标?

This might be a repeat of Fastest way to convert an iterator to a list , but your question is a bit different since you ask which is the most Pythonic. 这可能是将迭代器转换为列表最快方法的重复,但是您的问题有所不同,因为您询问哪个是最Python的。 The accepted answer is list(my_iterator) over [e for e in my_iterator] because the prior runs in C under the hood. 可接受的答案是list(my_iterator)超过[e for e in my_iterator]因为前一个在C的[e for e in my_iterator]运行。 One commenter suggests [*my_iterator] is faster than list(my_iterator) , so you might want to test that. 一位评论者建议[*my_iterator]list(my_iterator)快,因此您可能需要测试一下。 My general vote is that they are all equally Pythonic, so I'd go with the faster of the two for your use case. 我的普遍投票是,它们都是同样具有Python风格,因此在您的用例中,我会选择两者中较快的一个。 It's also possible that the older answer is out of date. 较旧的答案也可能过时。

After exploring more the subject I've come with some conclusions. 在探索了更多主题之后,我得出了一些结论。

There should be one-- and preferably only one --obvious way to do it 应该有一种-最好只有一种-显而易见的方法

( zen of python ) 禅宗的python

Deciding which option is the "pythonic" one should take into consideration some criteria : 确定哪个选项是“ pythonic”选项时,应考虑一些标准:

  • how explicit, 多么明确
  • simple, 简单,
  • and readable it is. 和可读性。

And the obvious "pythonic" option winning in all criteria is option number 3): 在所有条件下赢得的明显“ pythonic”选项是选项3):

list = list(my_iterator) 列表=列表(my_iterator)

Here is why is "obvious" that no 3) is the pythonic one: 这就是为什么“很明显”没有3)是pythonic的原因:

  • Option 3) is close to natural language making you to 'instantly' think what is the output. 选项3)接近自然语言,使您可以“立即”思考输出的内容。
  • Option 2) (using list comprehension) if you see for the first time that line of code will take you to read a little bit more and to pay a bit more attention. 选项2)(使用列表理解),如果您是第一次看到该行代码,将使您阅读更多一点并给予更多注意。 For example, I use list comprehension when I want to add some extra steps(calling a function with the iterated elements or having some checking using if statement), so when I see a list comprehension I check for any possible function call inside or for any if statment. 例如,当我想添加一些额外的步骤(使用迭代元素调用函数或使用if语句进行一些检查)时,我使用列表推导,因此当我看到列表推导时,我会检查内部是否存在任何可能的函数调用如果陈述。
  • option 1) (unpacking using *) asterisk operator can be a bit confusing if you don't use it regularly, there are 4 cases for using the asterisk in Python : 选项1)(使用*解压缩)如果您不经常使用星号运算符,可能会有些混乱, 在Python中4种情况使用星号

    1. For multiplication and power operations. 用于乘法和幂运算。
    2. For repeatedly extending the list-type containers. 用于重复扩展列表类型的容器。
    3. For using the variadic arguments. 用于使用可变参数。 (so-called “packing”) (所谓的“包装”)
    4. For unpacking the containers. 用于开箱。

Another good argument is python docs themselves, I have done some statistics to check which options are chosen by the docs, for this I've chose 4 buil-in iterators and everything from the module itertools (that are used like: itertools. ) to see how they are unpacked in a list: 另一个很好的论据是python文档本身,我已经做了一些统计数据来检查文档选择了哪些选项,为此,我选择了4个内置迭代器,以及从模块itertools (如itertools.到查看它们如何在列表中解压:

  • map 地图
  • range 范围
  • filter 过滤
  • enumerate 枚举
  • itertools. itertools。

After exploring the docs I found: 0 iterators unpacked in a list using option 1) and 2) and 35 using option 3). 浏览了文档之后,我发现:使用选项1)和2)在列表中解压缩了0个迭代器,使用选项3)解开了35个迭代器。

在此处输入图片说明

Conclusion : 结论

The pythonic way to unpack an iterator inside of a list is: my_list = list(my_iterator) 在列表中解压缩迭代器的my_list = list(my_iterator)是: my_list = list(my_iterator)

If you're interested in the least amount of typing possible, you can actually do one character better than my_list = [*my_iterator] with iterable unpacking: 如果您对尽可能少的键入感兴趣,那么实际上可以通过可迭代的拆包比my_list = [*my_iterator]做一个字符更好:

*my_list, = my_iterator

or (although this only equals my_list = [*my_iterator] in the number of characters): 或(尽管此字符数仅等于my_list = [*my_iterator] ):

[*my_list] = my_iterator

(Funny how it has the same effect as my_list = [*my_iterator] .) (有趣的是,它与my_list = [*my_iterator]具有相同的效果。)

For the most Pythonic solution, however, my_list = list(my_iterator) is clearly the clearest and the most readable of all, and should therefore be considered the most Pythonic. 但是,对于大多数Python语言的解决方案, my_list = list(my_iterator)显然是最清晰和最易读的,因此应被视为最具Python语言的。

While the unpacking operator * is not often used for unpacking a single iterable into a list (therefore [*it] is a bit less readable than list(it) ), it is handy and more Pythonic in several other cases: 虽然解包运算符*并不经常用于将单个可迭代对象解压缩到列表中(因此[*it]可读性比list(it) ),但在其他几种情况下,它很方便并且使用Python格式:

1. Unpacking an iterable into a single list / tuple / set, adding other values: 1.将迭代器解压缩为单个列表/元组/集合,并添加其他值:

mixed_list = [a, *it, b]

This is more concise and efficient than 这比

mixed_list = [a]
mixed_list.extend(it)
mixed_list.append(b)

2. Unpacking multiple iterables + values into a list / tuple / set 2.将多个可迭代项和值解压缩到列表/元组/集合中

mixed_list = [*it1, *it2, a, b, ... ]

This is similar to the first case. 这与第一种情况相似。

3. Unpacking an iterable into a list, excluding elements 3.将迭代器解压缩到列表中,不包括元素

first, *rest = it

This extracts the first element of it into first and unpacks the rest into a list. it其第一个元素提取为first然后将其余元素解压缩为列表。 One can even do 一个人甚至可以做

_, *mid, last = it

This dumps the first element of it into a don't-care variable _ , saves last element into last , and unpacks the rest into a list mid . 这转储的第一个元素it为不关心变量_ ,最后一个元素保存到last ,并解压休息到一个列表mid

4. Nested unpacking of multiple levels of an iterable in one statement 4.在一个语句中嵌套拆解多个级别的可迭代对象

it = (0, range(5), 3)
a1, (*a2,), a3 = it          # Unpack the second element of it into a list a2
e1, (first, *rest), e3 = it  # Separate the first element from the rest while unpacking it[1]

This can also be used in for statements: 也可以在for语句中使用:

from itertools import groupby

s = "Axyz123Bcba345D"
for k, (first, *rest) in groupby(s, key=str.isalpha):
    ...

I tend to use zip if I need to convert a list to a dictionary or use it as a key-value pair in a loop or list comprehension. 如果我需要将列表转换为字典或将其用作循环或列表理解中的键值对,则倾向于使用zip。

However, if this is only for illustration to create an iterator. 但是,如果这仅是为了说明创建迭代器。 I will definitely vote for #3 for clarity. 为了明确起见,我一定会投票给#3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM