Asterisco nella chiamata di funzione


111

Sto usando itertools.chain per "appiattire" un elenco di elenchi in questo modo:

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

in che modo è diverso dal dire:

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))

8
Dai un'occhiata alla decompressione degli elenchi di argomenti nella documentazione di Python per maggiori informazioni.
Kai

8
dovresti anche controllare l' **operatore: fa la stessa cosa *ma con gli argomenti delle parole chiave.
Sean Vieira

Risposte:


181

* è l'operatore "splat": prende un elenco come input e lo espande in argomenti posizionali effettivi nella chiamata di funzione.

Quindi, se lo uniqueCrossTabsera [ [ 1, 2 ], [ 3, 4 ] ], allora itertools.chain(*uniqueCrossTabs)è come direitertools.chain([ 1, 2 ], [ 3, 4 ])

Questo è ovviamente diverso dal semplice passaggio uniqueCrossTabs. Nel tuo caso, hai un elenco di elenchi che desideri appiattire; quello che itertools.chain()fa è restituire un iteratore sulla concatenazione di tutti gli argomenti posizionali che gli passi, dove ogni argomento posizionale è iterabile di per sé.

In altre parole, vuoi passare ogni elenco uniqueCrossTabscome argomento a chain(), che li concatenerà insieme, ma non hai gli elenchi in variabili separate, quindi usi l' *operatore per espandere l'elenco di elenchi in diversi argomenti di elenco.

Come Jochen Ritzel ha sottolineato nei commenti, chain.from_iterable()è più adatto per questa operazione, in quanto presuppone un singolo iterabile per cominciare. Il tuo codice diventa quindi semplicemente:

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

9
@larsmans: Penso che il termine sia più popolare nel mondo Ruby, ma sembra accettabile anche per Python, mi piace perché è divertente da dire ;-)
Cameron

1
@larsmans: interessante! Ho sempre pensato che si riferisse all'azione di decomprimere l'elenco in un elenco di argomenti, non al personaggio stesso.
Cameron

1
Forse le stringhe non sono il miglior esempio perché non tutti le vedono come iterabili. Btw: invece di chain(*it)scrivere chain.from_iterable(it).
Jochen Ritzel

@ Jochen: hai perfettamente ragione, lo cambierò per usare invece i numeri. Inoltre, non sapevo nemmeno che from_iterableesistesse! Lo aggiungerò a breve nella mia risposta
Cameron

1
@Ramy: *serve solo per esplodere l'elenco in argomenti posizionali per una funzione (quindi sì, molto specifico). Puoi fare for l in uniqueCrossTabs:per iterare su di loro. Sfortunatamenteèdifficile da vedere *al lavoro poiché funziona solo quando stai passando un elenco a una funzione (invece di passare l'elenco come primo parametro, *fa sì che ogni elemento nell'elenco venga passato come parametro separato, uno dopo l'altro , come se fossero stati digitati separati da virgole nell'elenco dei parametri)
Cameron

72

Divide la sequenza in argomenti separati per la chiamata di funzione.

>>> 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)

succinta spiegazione con esempi. +1!
AruniRC

28

Solo un modo alternativo per spiegare il concetto / usarlo.

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]

3
questo è importante e non viene menzionato altrove
Gershom

1
Questa risposta non si applica alla domanda in modo specifico, ma è un'importante applicazione dell'asterisco (quindi penso sia appropriata sotto il titolo piuttosto "nebbioso"). Sulla stessa linea, un'altra importante applicazione è nelle definizioni delle funzioni: def func(a, b, *args):vedere questa risposta per maggiori informazioni.
ASL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.