web-dev-qa-db-fra.com

Comment décompresser un tuple de longueur n à m <n variables

Dans Python 3 je peux faire ce qui suit (voir aussi PEP3132 on Extended Iterable Unpacking):

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

Que puis-je faire pour obtenir la même élégance similaire dans Python 2.x?


Je sais que je pourrais utiliser des opérations d'accès et de découpage d'un seul élément, mais je me demande s'il y a une manière plus Pythonique . Mon code jusqu'à présent:

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

J'ai découvert que le PEP3132 donne quelques exemples pour Python 2.x également:

De nombreux algorithmes nécessitent de diviser une séquence en une paire "premier repos":

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

[...]

De plus, si la valeur de droite n'est pas une liste, mais un itérable, elle doit être convertie en liste avant de pouvoir effectuer un découpage; pour éviter de créer cette liste temporaire, il faut recourir à

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

Autres approches données dans les réponses à cette question:

Approche de décompression de la liste des arguments de fonction

nécessite une définition/appel de fonction supplémentaire:

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

Je me demande pourquoi il est implémenté dans les listes d'arguments de la fonction de déballage, mais pas pour le déballage normal des tuples.

Approche par générateur

Crédits . Nécessite également une implémentation de fonction personnalisée. Est un peu plus flexible concernant le nombre de variables d'abord.

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)

Les plus pythoniques seraient probablement ceux mentionnés dans le PEP ci-dessus, je suppose?

30
moooeeeep

J'ai cette petite fonction pratique:

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

Par exemple:

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

fonctionne également avec moins d'arguments:

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

En réponse au commentaire, vous pouvez également définir:

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

et utilisez-le comme ceci:

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

Je me trompe peut-être mais pour autant que je sache

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

est juste du sucre syntaxique pour trancher et indexer des tuples. Je le trouve utile mais pas très explicite.

8
Félix Cantournet

Je ne pense pas qu'il y ait de meilleur moyen que celui que vous avez posté mais voici une alternative en utilisant iter

>>> x = (1,2,3)
>>> i = iter(x)
>>> a,b = next(i), Tuple(i)
>>> a
1
>>> b
(2, 3)
4
jamylak

Vous n'êtes pas sûr du contexte, mais qu'en est-il de .pop (0)?

Je vois qu'il y a des tuples dans votre exemple, mais si vous voulez faire le genre de choses que vous faites, les listes seraient plus adaptées, je pense? (À moins qu'il n'y ait une bonne raison pour qu'ils soient immuables, ils ne sont pas donnés dans la question.)

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