Asterisk dalam pemanggilan fungsi

111

Saya menggunakan itertools.chain untuk "meratakan" daftar daftar dengan cara ini:

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

bagaimana ini berbeda dengan mengatakan:

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))
Ramy
sumber
8
Lihatlah daftar argumen pembongkaran di dokumen Python untuk informasi lebih lanjut.
Kai
8
Anda juga harus memeriksa **operator - ini melakukan hal yang sama seperti *tetapi dengan argumen kata kunci.
Sean Vieira

Jawaban:

181

* adalah operator "percikan": Ini mengambil daftar sebagai masukan, dan mengembangkannya menjadi argumen posisi aktual dalam pemanggilan fungsi.

Jadi jika uniqueCrossTabsdulu [ [ 1, 2 ], [ 3, 4 ] ], maka itertools.chain(*uniqueCrossTabs)sama saja dengan mengatakanitertools.chain([ 1, 2 ], [ 3, 4 ])

Ini jelas berbeda dengan mengoper uniqueCrossTabs. Dalam kasus Anda, Anda memiliki daftar daftar yang ingin Anda ratakan; apa yang itertools.chain()dilakukan adalah mengembalikan iterator atas rangkaian semua argumen posisi yang Anda berikan padanya, di mana setiap argumen posisi dapat diulang dengan sendirinya.

Dengan kata lain, Anda ingin meneruskan setiap daftar uniqueCrossTabssebagai argumen chain(), yang akan menyatukannya, tetapi Anda tidak memiliki daftar dalam variabel terpisah, jadi Anda menggunakan* operator untuk memperluas daftar daftar menjadi beberapa argumen daftar.

Seperti yang ditunjukkan Jochen Ritzel di komentar, chain.from_iterable()lebih cocok untuk operasi ini, karena mengasumsikan satu iterable untuk memulai. Kode Anda kemudian menjadi:

uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))
Cameron
sumber
9
@larsmans: Saya pikir istilah ini lebih populer di dunia Ruby, tetapi tampaknya juga dapat diterima untuk Python. Saya suka karena menyenangkan untuk mengatakannya ;-)
Cameron
1
@larsmans: Menarik! Saya selalu berpikir ini merujuk pada tindakan membongkar daftar menjadi daftar argumen, bukan karakter sebenarnya.
Cameron
1
Mungkin string bukan contoh terbaik karena tidak semua orang melihat string sebagai iterable. Btw: Daripada chain(*it)saya menulis chain.from_iterable(it).
Jochen Ritzel
@Jochen: Anda benar, saya akan mengubahnya untuk menggunakan angka sebagai gantinya. Juga, saya bahkan tidak tahu from_iterableada! Saya akan segera menambahkannya ke jawaban saya
Cameron
1
@Ramy: *hanya untuk meledakkan daftar menjadi argumen posisi ke suatu fungsi (jadi ya, sangat spesifik). Anda dapat melakukannya for l in uniqueCrossTabs:untuk mengulanginya. Sayangnya sulit untuk melihat *di tempat kerja karena ini hanya berfungsi ketika Anda meneruskan daftar ke suatu fungsi (alih-alih meneruskan daftar sebagai parameter pertama, *menyebabkan setiap elemen dalam daftar diteruskan sebagai parameter terpisah, satu demi satu , seolah-olah telah diketik dipisahkan dengan koma dalam daftar parameter)
Cameron
72

Ini membagi urutan menjadi argumen terpisah untuk pemanggilan fungsi.

>>> 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
sumber
penjelasan yang lengkap dengan contoh-contoh. +1!
AruniRC
28

Hanya cara alternatif untuk menjelaskan konsep / menggunakannya.

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
sumber
3
ini penting dan tidak disebutkan di tempat lain
Gershom
1
Jawaban ini tidak berlaku untuk pertanyaan secara khusus, tetapi merupakan aplikasi penting dari tanda bintang (jadi menurut saya cocok dengan judul yang agak "kabur"). Sejalan dengan itu, aplikasi penting lainnya ada dalam definisi fungsi: def func(a, b, *args):Lihat jawaban ini untuk info lebih lanjut.
ASL