Astérisque dans l'appel de fonction

111

J'utilise itertools.chain pour "aplatir" une liste de listes de cette façon:

uniqueCrossTabs = list(itertools.chain(*uniqueCrossTabs))

en quoi est-ce différent de dire:

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))
Ramy
la source
8
Jetez un œil à la décompression des listes d'arguments dans la documentation Python pour plus d'informations.
Kai
8
vous devriez également vérifier l' **opérateur - il fait la même chose que *mais avec des arguments de mot-clé.
Sean Vieira

Réponses:

181

* est l'opérateur "splat": il prend une liste comme entrée et l'étend en arguments positionnels réels dans l'appel de fonction.

Donc si uniqueCrossTabsc'était le cas [ [ 1, 2 ], [ 3, 4 ] ], alors itertools.chain(*uniqueCrossTabs)c'est la même chose que de direitertools.chain([ 1, 2 ], [ 3, 4 ])

C'est évidemment différent du passage juste uniqueCrossTabs. Dans votre cas, vous avez une liste de listes que vous souhaitez aplatir; ce qui itertools.chain()fait est de retourner un itérateur sur la concaténation de tous les arguments positionnels que vous lui passez, où chaque argument positionnel est itérable à part entière.

En d'autres termes, vous voulez passer chaque liste en uniqueCrossTabstant qu'argument à chain(), ce qui les enchaînera, mais vous n'avez pas les listes dans des variables séparées, vous utilisez donc le* opérateur pour développer la liste des listes en plusieurs arguments de liste.

Comme Jochen Ritzel l'a souligné dans les commentaires, chain.from_iterable()est mieux adapté pour cette opération, car elle suppose un seul itérable d'itérables pour commencer. Votre code devient alors simplement:

uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))
Cameron
la source
9
@larsmans: Je pense que le terme est plus populaire dans le monde Ruby, mais il semble être acceptable pour Python aussi je l'aime parce que c'est amusant à dire ;-)
Cameron
1
@larsmans: Intéressant! J'ai toujours pensé que cela faisait référence à l'action de décompresser la liste dans une liste d'arguments, pas au personnage lui-même.
Cameron
1
Peut-être que les chaînes ne sont pas le meilleur exemple car tout le monde ne voit pas les chaînes comme des itérables. Btw: Au lieu d' chain(*it)écrire chain.from_iterable(it).
Jochen Ritzel
@Jochen: Vous avez absolument raison, je vais le changer pour utiliser des nombres à la place. De plus, je ne savais même pas qu'il from_iterableexistait! Je vais l'ajouter dans ma réponse sous peu
Cameron
1
@Ramy: *sert uniquement à décomposer la liste en arguments positionnels vers une fonction (donc oui, très spécifique). Vous pouvez faire for l in uniqueCrossTabs:pour les parcourir. Malheureusement, c'est difficile à voir *au travail car cela ne fonctionne que lorsque vous passez une liste à une fonction (au lieu de passer la liste comme premier paramètre, *fait passer chaque élément de la liste en tant que paramètre séparé, l'un après l'autre , comme s'ils avaient été tapés séparés par des virgules dans la liste des paramètres)
Cameron
72

Il divise la séquence en arguments séparés pour l'appel de fonction.

>>> def foo(a, b=None, c=None):
...   print a, b, c
... 
>>> foo([1, 2, 3])
[1, 2, 3] None None
>>> foo(*[1, 2, 3])
1 2 3
>>> def bar(*a):
...   print a
... 
>>> bar([1, 2, 3])
([1, 2, 3],)
>>> bar(*[1, 2, 3])
(1, 2, 3)
Ignacio Vazquez-Abrams
la source
explication succincte avec des exemples. +1!
AruniRC
28

Juste une manière alternative d'expliquer le concept / de l'utiliser.

import random

def arbitrary():
    return [x for x in range(1, random.randint(3,10))]

a, b, *rest = arbitrary()

# a = 1
# b = 2
# rest = [3,4,5]
Gelbander
la source
3
ceci est important et non mentionné ailleurs
Gershom
1
Cette réponse ne s'applique pas spécifiquement à la question, mais est une application importante de l'astérisque (donc je pense qu'elle est appropriée sous le titre plutôt «brumeux»). Dans le même ordre d'idées, une autre application importante concerne les définitions de fonctions: def func(a, b, *args):consultez cette réponse pour plus d'informations.
ASL