【问题标题】:How to unpack tuple of length n to m<n variables [duplicate]如何将长度为 n 的元组解压缩为 m<n 个变量 [重复]
【发布时间】:2012-04-24 14:08:41
【问题描述】:

在 Python 3 中,我可以执行以下操作(另请参阅 PEP3132 关于扩展可迭代解包):

a, *b = (1, 2, 3)
# a = 1; b = (2, 3)

我可以做些什么来在 Python 2.x 中实现同样的优雅?


我知道我可以使用单元素访问和切片操作,但我想知道是否有更多的 pythonic 方式。到目前为止我的代码:

a, b = (1, 2, 3)[0], (1, 2, 3)[1:]
# a = 1; b = (2, 3)

【问题讨论】:

  • 似乎是显式切片,或者使用多个匿名_下划线变量来捕获不需要的值:x、_、_ = tup
  • 我实际上对这个功能有疑问。是否符合python“显胜于隐”的禅意?
  • @jdi 它明确指出:将第一个项目交给a,将所有其他项目交给b。我觉得这很清楚......
  • 这可能是重复的:stackoverflow.com/q/5333680/1025391

标签: python iterable-unpacking


【解决方案1】:

我发现相关的PEP3132 也提供了一些 Python 2.x 的示例:

许多算法都需要将序列拆分为“第一,后”对:

first, rest = seq[0], seq[1:]

[...]

另外,如果右边的值不是一个列表,而是一个可迭代的,则必须先将其转换为列表,然后才能进行切片;为了避免创建这个临时列表,必须求助于

it = iter(seq)
first = it.next()
rest = list(it)

这个问题的答案中给出的其他方法:

函数参数列表解包方法

需要额外的函数定义/调用:

def unpack(first, *rest): 
  return first, rest
first, rest = unpack( *seq )

我想知道为什么它是在解包函数参数列表中实现的,而不是在正常的元组解包中实现。

生成器方法

Credits。还需要自定义函数实现。 first 变量的数量更灵活一些。

def unpack_nfirst(seq, nfirst):
  it = iter(seq)
  for x in xrange(nfirst):
    yield next(it, None)
  yield tuple(it)
first, rest = unpack_nfirst(seq, 1)

我猜,最 Python 的可能是上面 PEP 中提到的那些?

【讨论】:

  • 截至今天,PEP 3132 似乎只适用于 Python 3.x。我可以确认 'first, *rest = seq' 语法在 Python 2.7.5 中不起作用(您在上面提到了 2.x)。
  • @Dave 感谢您再次提出这个问题。我决定从引用的部分中删除该部分,因为它会造成混淆,并且与答案无关。
【解决方案2】:

我可能错了,但据我所知

a, *b = (1, 2, 3)

只是用于切片和索引元组的语法糖。我觉得它很有用,但不是很明确。

【讨论】:

  • 老实说,我还在 py2.7 上,还没有看到这个 3.x 的添加。它甚至看起来并不比切片有用得多。你显然知道你想要第一个元素。比起糖更喜欢切片。
  • 虽然它可能只是糖,但如果左边的列表大于 2(嗯,可能大于 6 或 7),它就变得更重要了。切片的问题是您必须在= 的两侧进行一些手动计数,这可能会使代码更难维护。
  • 我有一个列表列表,每个列表的长度为 4 或更多,我希望我可以在 python2.7 中做到这一点:for a, b, c, d, *unused in myList: &lt;do work with a, b, c, d&gt;。使用适当的 a、b、c、d 名称,我发现它比必须索引单个变量更具表现力。
  • @mcmlxxxvi 确实,命名是(难)而且更好。我撤回我的声明。
【解决方案3】:

我有这个方便的小功能:

def just(n, seq):
    it = iter(seq)
    for _ in range(n - 1):
        yield next(it, None)
    yield tuple(it)

例如:

a, b, c = just(3, range(5))
print a, b, c
## 0 1 (2, 3, 4)

也适用于更少的参数:

a, b, c = just(3, ['X', 'Y'])
print a, b, c
## X Y ()

针对评论,您还可以定义:

def take2(a, *rest): return a, rest
def take3(a, b, *rest): return a, b, rest
def take4(a, b, c, *rest): return a, b, rest
... etc

并像这样使用它:

p = (1,2,3)
a, b = take2(*p)
print a, b
## 1 (2, 3)

【讨论】:

  • 这让我想到了这个想法:def foo(x, *y): return x, y,它会是a, b = foo( *(1,2,3) ) ...
  • @moooeeeep 好主意,但您可以简单地使用a,b = foo(1,2,3) 而不是a, b = foo( *(1,2,3) )
  • @moooeeeep:查看更新))
  • 在生产代码中,您将这个方便的小功能保存在哪个文件中?同一个文件?不同的文件?进口什么?你把它和它的朋友打包吗?所以总的来说,当您访问just 时,它在实际代码中的外观如何?
  • @naxa:例如import myTools .... a,b = myTools.just(...)
【解决方案4】:

我认为没有比您发布的方法更好的方法了,但这里有一个使用 iter 的替代方法

>>> x = (1,2,3)
>>> i = iter(x)
>>> a,b = next(i), tuple(i)
>>> a
1
>>> b
(2, 3)

【讨论】:

    【解决方案5】:

    不确定上下文,但是 .pop(0) 呢?

    我看到你的例子中有元组,但如果你想做你所做的那种事情,我认为列表会更合适? (除非有充分的理由让它们在问题中不可变。)

    b = [1,2,3]
    a = b.pop(0)
    

    【讨论】:

      猜你喜欢
      • 2014-12-24
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-04
      • 2016-01-08
      • 2022-11-14
      • 1970-01-01
      相关资源
      最近更新 更多