Meskipun sangat menarik, teknik ini harus bertentangan dengan nilai inti "keterbacaan" dari Python!
Demis
Jawaban:
108
iter()adalah iterator yang berurutan. [x] * nmenghasilkan daftar yang berisi nkuantitas x, yaitu daftar panjang n, di mana setiap elemen berada x. *argmembongkar urutan menjadi argumen untuk panggilan fungsi. Oleh karena itu, Anda meneruskan iterator yang sama 3 kali ke zip(), dan itu menarik item dari iterator setiap saat.
Perlu diketahui: ketika iterator yields (= returns) item, Anda dapat membayangkan item ini sebagai "dikonsumsi". Jadi pada saat iterator dipanggil, itu menghasilkan item "tidak dikonsumsi" berikutnya.
winklerrr
46
Jawaban dan komentar hebat lainnya menjelaskan dengan baik peran argument unpacking dan zip () .
Seperti yang dikatakan Ignacio dan ujukatzel , Anda meneruskan ke zip()tiga referensi ke iterator yang sama dan zip()membuat 3-tupel dari bilangan bulat — secara berurutan — dari setiap referensi ke iterator:
Dan karena Anda meminta contoh kode yang lebih panjang:
chunk_size =3
L =[1,2,3,4,5,6,7,8,9]# iterate over L in steps of 3for start in range(0,len(L),chunk_size):# xrange() in 2.x; range() in 3.x
end = start + chunk_sizeprint L[start:end]# three-item chunks
Mengikuti nilai startdan end:
[0:3)#[1,2,3][3:6)#[4,5,6][6:9)#[7,8,9]
FWIW, Anda bisa mendapatkan hasil yang sama dengan map()argumen awal None:
Saya pikir satu hal yang terlewat di semua jawaban (mungkin jelas bagi mereka yang akrab dengan iterator) tetapi tidak begitu jelas bagi orang lain adalah -
Karena kita memiliki iterator yang sama, itu dikonsumsi dan elemen yang tersisa digunakan oleh zip. Jadi jika kita hanya menggunakan daftar dan bukan iter misalnya.
l = range(9)
zip(*([l]*3))# note: not an iter here, the lists are not emptied as we iterate # output [(0,0,0),(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),(6,6,6),(7,7,7),(8,8,8)]
Dengan menggunakan iterator, munculkan nilai dan hanya tetap tersedia, jadi untuk zip setelah 0 dikonsumsi 1 tersedia dan kemudian 2 dan seterusnya. Hal yang sangat halus, tapi cukup pintar !!!
+1, Anda menyelamatkan saya! Saya tidak percaya bahwa jawaban lain melewatkan detail penting ini dengan asumsi semua orang tahu ini. Dapatkah Anda memberikan referensi ke dokumentasi yang menyertakan informasi ini?
Snehasish Karmakar
9
iter(s) mengembalikan iterator untuk s.
[iter(s)]*n membuat daftar n kali iterator yang sama untuk s.
Jadi, saat melakukannya zip(*[iter(s)]*n), ia mengekstrak item dari ketiga iterator dari daftar secara berurutan. Karena semua iterator adalah objek yang sama, itu hanya mengelompokkan daftar dalam potongan n.
Bukan 'n iterator dari daftar yang sama', tetapi 'n kali objek iterator yang sama'. Objek iterator yang berbeda tidak berbagi status, meskipun mereka berada dalam daftar yang sama.
Thomas Wouters
Terima kasih, dikoreksi. Memang itulah yang saya "pikirkan", tetapi menulis sesuatu yang lain.
sttwister
6
Satu kata nasihat untuk menggunakan zip dengan cara ini. Ini akan memotong daftar Anda jika panjangnya tidak dapat dibagi rata. Untuk mengatasi ini, Anda dapat menggunakan itertools.izip_longest jika Anda dapat menerima nilai isian. Atau Anda bisa menggunakan sesuatu seperti ini:
Mungkin lebih mudah untuk melihat apa yang terjadi dengan interpreter python atau ipythondengan n = 2:
In[35]:[iter("ABCDEFGH")]*2Out[35]:[<iterator at 0x6be4128>,<iterator at 0x6be4128>]
Jadi, kami memiliki daftar dua iterator yang menunjuk ke objek iterator yang sama. Ingatlah bahwa iterpada suatu objek mengembalikan objek iterator dan dalam skenario ini, itu adalah iterator yang sama dua kali karena *2gula sintaksis python. Iterator juga hanya berjalan sekali.
Selanjutnya, zipmengambil sejumlah iterable ( urutan adalah iterable ) dan membuat tupel dari elemen ke-i dari masing-masing urutan masukan. Karena kedua iterator identik dalam kasus kita, zip memindahkan iterator yang sama dua kali untuk setiap tupel 2-elemen keluaran.
In[41]: help(zip)Help on built-in function zip in module __builtin__:
zip(...)
zip(seq1 [, seq2 [...]])->[(seq1[0], seq2[0]...),(...)]Return a list of tuples, where each tuple contains the i-th elementfrom each of the argument sequences.The returned list is truncatedin length to the length of the shortest argument sequence.
Operator unpacking ( *) memastikan bahwa iterator berjalan hingga habis yang dalam hal ini sampai tidak ada cukup input untuk membuat tupel 2 elemen.
Ini dapat diperluas ke nilai apa pun ndan zip(*[iter(s)]*n)berfungsi seperti yang dijelaskan.
Maaf karena lambat. Tapi bisakah Anda menjelaskan "iterator yang sama dua kali karena * 2 python syntactic sugar. Iterator juga hanya berjalan sekali." tolong berpisah? Kalau begitu kok hasilnya bukan [("A", "A") ....]? Terima kasih.
Bowen Liu
@BowenLiu *hanyalah kemudahan untuk menduplikasi objek. Cobalah dengan skalar dan kemudian dengan daftar. Juga mencoba print(*zip(*[iter("ABCDEFG")]*2))vs print(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")])). Kemudian mulailah membagi keduanya menjadi langkah-langkah yang lebih kecil untuk melihat apa sebenarnya objek iterator dalam kedua pernyataan tersebut.
Jawaban:
iter()
adalah iterator yang berurutan.[x] * n
menghasilkan daftar yang berisin
kuantitasx
, yaitu daftar panjangn
, di mana setiap elemen beradax
.*arg
membongkar urutan menjadi argumen untuk panggilan fungsi. Oleh karena itu, Anda meneruskan iterator yang sama 3 kali kezip()
, dan itu menarik item dari iterator setiap saat.sumber
yield
s (=return
s) item, Anda dapat membayangkan item ini sebagai "dikonsumsi". Jadi pada saat iterator dipanggil, itu menghasilkan item "tidak dikonsumsi" berikutnya.Jawaban dan komentar hebat lainnya menjelaskan dengan baik peran argument unpacking dan zip () .
Seperti yang dikatakan Ignacio dan ujukatzel , Anda meneruskan ke
zip()
tiga referensi ke iterator yang sama danzip()
membuat 3-tupel dari bilangan bulat — secara berurutan — dari setiap referensi ke iterator:Dan karena Anda meminta contoh kode yang lebih panjang:
Mengikuti nilai
start
danend
:FWIW, Anda bisa mendapatkan hasil yang sama dengan
map()
argumen awalNone
:Untuk lebih lanjut tentang
zip()
danmap()
: http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/sumber
Saya pikir satu hal yang terlewat di semua jawaban (mungkin jelas bagi mereka yang akrab dengan iterator) tetapi tidak begitu jelas bagi orang lain adalah -
Karena kita memiliki iterator yang sama, itu dikonsumsi dan elemen yang tersisa digunakan oleh zip. Jadi jika kita hanya menggunakan daftar dan bukan iter misalnya.
Dengan menggunakan iterator, munculkan nilai dan hanya tetap tersedia, jadi untuk zip setelah 0 dikonsumsi 1 tersedia dan kemudian 2 dan seterusnya. Hal yang sangat halus, tapi cukup pintar !!!
sumber
iter(s)
mengembalikan iterator untuk s.[iter(s)]*n
membuat daftar n kali iterator yang sama untuk s.Jadi, saat melakukannya
zip(*[iter(s)]*n)
, ia mengekstrak item dari ketiga iterator dari daftar secara berurutan. Karena semua iterator adalah objek yang sama, itu hanya mengelompokkan daftar dalam potongann
.sumber
Satu kata nasihat untuk menggunakan zip dengan cara ini. Ini akan memotong daftar Anda jika panjangnya tidak dapat dibagi rata. Untuk mengatasi ini, Anda dapat menggunakan itertools.izip_longest jika Anda dapat menerima nilai isian. Atau Anda bisa menggunakan sesuatu seperti ini:
Pemakaian:
Cetakan:
sumber
itertools
resep: docs.python.org/2/library/itertools.html#recipesgrouper
. Tidak perlu menemukan kembali rodaMungkin lebih mudah untuk melihat apa yang terjadi dengan interpreter python atau
ipython
dengann = 2
:Jadi, kami memiliki daftar dua iterator yang menunjuk ke objek iterator yang sama. Ingatlah bahwa
iter
pada suatu objek mengembalikan objek iterator dan dalam skenario ini, itu adalah iterator yang sama dua kali karena*2
gula sintaksis python. Iterator juga hanya berjalan sekali.Selanjutnya,
zip
mengambil sejumlah iterable ( urutan adalah iterable ) dan membuat tupel dari elemen ke-i dari masing-masing urutan masukan. Karena kedua iterator identik dalam kasus kita, zip memindahkan iterator yang sama dua kali untuk setiap tupel 2-elemen keluaran.Operator unpacking (
*
) memastikan bahwa iterator berjalan hingga habis yang dalam hal ini sampai tidak ada cukup input untuk membuat tupel 2 elemen.Ini dapat diperluas ke nilai apa pun
n
danzip(*[iter(s)]*n)
berfungsi seperti yang dijelaskan.sumber
*
hanyalah kemudahan untuk menduplikasi objek. Cobalah dengan skalar dan kemudian dengan daftar. Juga mencobaprint(*zip(*[iter("ABCDEFG")]*2))
vsprint(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")]))
. Kemudian mulailah membagi keduanya menjadi langkah-langkah yang lebih kecil untuk melihat apa sebenarnya objek iterator dalam kedua pernyataan tersebut.