【问题标题】:Idiomatic way to unpack variable length list of maximum size n解压缩最大大小为 n 的可变长度列表的惯用方法
【发布时间】:2013-12-10 17:38:23
【问题描述】:

我正在读取一个文件并像这样解压缩每一行:

for line in filter(fh):
  a, b, c, d = line.split()

但是,与我希望解包的变量相比,该行的列可能更多或更少。在较少的情况下,我想将None 分配给悬空变量,而在更多的情况下,我想忽略它们。这样做的惯用方法是什么?我正在使用 python 2.7。

【问题讨论】:

标签: python iterable-unpacking


【解决方案1】:

修复列表的长度,用None填充。

def fixLength(lst, length):
    return (lst + [None] * length)[:length]

【讨论】:

    【解决方案2】:

    在 python 3 中你可以使用这个

    a, b, c, d, *_unused_ = line.split() + [None]*4
    

    编辑

    对于大字符串,我建议使用maxsplit-argument 进行拆分(此参数也适用于py2.7):

    a, b, c, d, *_unused_ = line.split(None, 4) + [None]*4
    

    为什么是 5?否则,第 4 个元素将包含该行的整个残差。

    Edit2 是 4... 它在 4 次拆分后停止,而不是 4 个元素

    【讨论】:

    • @Marcin 我也没有在你的情况下得到它。
    • 这是 python 3 的一个不错的功能,我希望我可以使用它!唉,蟒蛇2
    • 至少从 python 2.7.5 开始,str.split 将 maxsplit 作为位置参数,而不是关键字参数。所以它是line.split(None, 5),但仍然是一个很好的补充。
    • @pythonicmetaphor 你是对的。更改了它,因此拆分将在两个版本中都有效。我对 maxsplit-number 的解释是错误的,也改了。很抱歉给大家带来这么多的困惑……
    【解决方案3】:

    首先,想想你为什么要这样做。

    但是,假设您想 (1) 使用 None 填充和 (2) 忽略额外的变量,代码很简单:

    a,b,c,d = (line.split() + [None]*4)[:4]
    

    显然,幻数必须与变量数相同。这将使用幻数扩展您所拥有的内容,然后缩减到该长度。

    对于任意可迭代,您可以这样做:

    import itertools
    
    def padslice(seq,n):
        return itertools.islice(itertools.chain(seq,itertools.repeat(None)), n)
    

    这是与 itertools 相同的 pad-and-slice。

    【讨论】:

    • +1 表示 python-2.7-one-liner。 (不是补偿,严重)。但是看看你的 padslice 函数。它不返回序列,但我认为为了解包你需要一个列表或类似的东西。
    • @koffein 您可以从生成器中解压,所以没有问题。
    • 您的第一个答案与我正在做的类似,这是可行的,但感觉不太习惯,因为它不适用于迭代器。但我喜欢你的第二个答案,这对我来说越来越接近蟒蛇了。
    • @Marcin 对。测试它并且它工作......很好的功能
    • @pythonicmetaphor 惯用的 python 不必使用迭代器,尤其是在已知类型不是迭代器的情况下。但是,谢谢。
    【解决方案4】:

    在 Python 3 中,您可以使用 itertools.zip_longest,如下所示:

    from itertools import zip_longest
    
    max_params = 4
    
    lst = [1, 2, 3, 4]
    a, b, c, d = next(zip(*zip_longest(lst, range(max_params))))
    print(f'{a}, {b}, {c}, {d}') # 1, 2, 3, 4
    
    lst = [1, 2, 3]
    a, b, c, d = next(zip(*zip_longest(lst, range(max_params))))
    print(f'{a}, {b}, {c}, {d}') # 1, 2, 3, None
    

    对于 Python 2.x,您可以关注此answer

    【讨论】:

      【解决方案5】:

      类似这样的东西,适用于任何可迭代/迭代器。如果您总是要传递一个列表,那么您可以删除 islice 部分。

      from itertools import islice
      def solve(seq, n):
          lis = list(islice(seq, n))
          return lis + [None]*(n - len(lis))
      ... 
      >>> a, b, c, d = solve(range(2), 4)
      >>> a, b, c, d
      (0, 1, None, None)
      >>> a, b, c, d = solve('qwe', 4)
      >>> a, b, c, d
      ('q', 'w', 'e', None)
      >>> a, b, c, d = solve(iter([1, 2, 3, 4, 5]), 4)
      >>> a, b, c, d
      (1, 2, 3, 4)
      

      【讨论】:

      • 您能否重命名该函数,使其看起来像您将在代码中使用的所有东西,惯用
      • 为什么要在填充之前切片?
      • @Marcin 也支持迭代器,如果迭代器包含多个 n 项,则无需读取所有项。
      • @AshwiniChaudhary 使用 itertools,您无需提前阅读。这就是重点。
      • @Marcin 我首先将该迭代器转换为列表,因此需要切片。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多