【问题标题】:Pythonic way to unpack an iterator inside of a list在列表中解压迭代器的 Pythonic 方法
【发布时间】:2020-01-13 17:59:54
【问题描述】:

我正在尝试找出 pythonic 在列表中解压缩迭代器的方法。

例如:

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

我提供了以下方法来将我的迭代器解压到一个列表中:

1)

my_list = [*my_iterator]

2)

my_list = [e for e in my_iterator]

3)

my_list = list(my_iterator)

No 1) 是我最喜欢的方式,因为它的代码更少,但我想知道这是否也是 pythonic 方式。或者除了pythonic方式之外,还有另一种方法可以实现吗?

【问题讨论】:

  • 选项 3 是 2to3 使用的选项(参见例如 echo "zip([1],[2])" | 2to3 -),因此会投赞成票。
  • @OlvinR​​oght 在我过去对 Python 3 的所有测试中,[*it] 总是最快的。它比list(it) 稍快,因为后者在查找list 函数时开销很小。但是差异很小,只有在输出列表的大小很小时才会显示出来。

标签: python python-3.x list unpack iterable-unpacking


【解决方案1】:

这可能是Fastest way to convert an iterator to a list 的重复,但你的问题有点不同,因为你问哪个是最 Pythonic 的。接受的答案是list(my_iterator) 而不是[e for e in my_iterator],因为先前在 C 引擎下运行。一位评论者建议[*my_iterator]list(my_iterator) 快,所以你可能想测试一下。我的普遍投票是它们都同样是 Pythonic,所以对于您的用例,我会选择两者中较快的一个。旧答案也可能已过时。

【讨论】:

    【解决方案2】:

    在探索了更多的主题之后,我得出了一些结论。

    应该有一种——最好只有一种——明显的方法

    (zen of python)

    决定哪个选项是“pythonic”应该考虑一些标准:

    • 多么明确,
    • 简单,
    • 并且可读。

    在所有标准中明显获胜的“pythonic”选项是选项号 3):

    list = list(my_iterator)

    这就是为什么“很明显”没有 3) 是 pythonic 的原因:

    • 选项 3) 接近自然语言,让您“立即” 想想输出是什么。
    • 选项 2)(使用列表理解)如果您是第一次看到 那行代码会带你多读一点,然后付钱 多一点关注。例如,当我使用列表推导时 想要添加一些额外的步骤(使用迭代调用函数 元素或使用 if 语句进行一些检查),所以当我看到 列表理解我检查内部是否有任何可能的函数调用或 对于任何 if 语句。
    • 选项 1)(使用 * 解包)星号运算符可能有点混乱 如果你不经常使用,还有4 cases for using the asterisk in Python

      1. 用于乘法和幂运算。
      2. 用于重复扩展列表型容器。
      3. 用于使用可变参数。 (所谓的“打包”)
      4. 用于拆箱。

    另一个很好的论点是 python docs 他们自己,我已经做了一些统计来检查文档选择了哪些选项,为此我选择了 4 个内置迭代器和模块 itertools 中的所有内容(使用喜欢:itertools.) 以查看它们是如何在列表中解压的:

    • 地图
    • 范围
    • 过滤器
    • 枚举
    • itertools.

    在浏览文档后,我发现:使用选项 1) 和 2) 在列表中解压缩了 0 个迭代器,使用选项 3) 解压缩了 35 个迭代器。

    结论

    在列表中解压迭代器的 Python 方法是:my_list = list(my_iterator)

    【讨论】:

      【解决方案3】:

      如果您对尽可能少的输入感兴趣,您实际上可以通过迭代解包比my_list = [*my_iterator] 更好地完成一个字符:

      *my_list, = my_iterator
      

      或者(虽然这在字符数上只等于my_list = [*my_iterator]):

      [*my_list] = my_iterator
      

      (有趣的是它与my_list = [*my_iterator]的效果相同。)

      然而,对于最 Pythonic 的解决方案,my_list = list(my_iterator) 显然是最清晰和最易读的,因此应该被认为是最 Pythonic 的。

      【讨论】:

        【解决方案4】:

        虽然解包运算符* 不常用于将单个可迭代对象解包到列表中(因此[*it] 的可读性不如list(it)),但在其他几种情况下它很方便且更具Pythonic:

        1。将可迭代解包到单个列表/元组/集合中,添加其他值:

        mixed_list = [a, *it, b]
        

        这样比

        更简洁高效
        mixed_list = [a]
        mixed_list.extend(it)
        mixed_list.append(b)
        

        2。将多个 iterables + 值解包到一个列表/元组/集合中

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

        这与第一种情况类似。

        3。将一个可迭代对象解包到一个列表中,不包括元素

        first, *rest = it
        

        这会将it 的第一个元素提取到first 中,并将其余元素解包到一个列表中。甚至可以做

        _, *mid, last = it
        

        这会将it 的第一个元素转储到无关变量_,将最后一个元素保存到last,并将其余元素解压缩到列表mid

        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]
        

        这也可以用在for 语句中:

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

        【讨论】:

          【解决方案5】:

          如果我需要将列表转换为字典或将其用作循环或列表理解中的键值对,我倾向于使用 zip。

          但是,如果这只是为了说明创建迭代器。为了清楚起见,我一定会投票给 #3

          【讨论】:

            猜你喜欢
            • 2012-01-30
            • 2017-12-16
            • 1970-01-01
            • 2021-01-11
            • 2020-07-12
            • 2012-04-16
            • 1970-01-01
            • 2021-12-10
            • 2012-10-12
            相关资源
            最近更新 更多