Mengapa mengiris substring dengan indeks di luar jangkauan berfungsi?

90

Mengapa tidak 'example'[999:9999]menghasilkan kesalahan? Sejak'example'[9] itu, apa motivasi dibaliknya?

Dari perilaku ini saya dapat berasumsi bahwa 'example'[3]pada dasarnya / secara internal tidak sama 'example'[3:4], meskipun keduanya menghasilkan 'm'string yang sama .

ijverig
sumber
17
[999:9999]bukanlah indeks, itu sepotong, dan memiliki semantik yang berbeda. Dari intro python: "Indeks irisan yang menurun ditangani dengan baik: indeks yang terlalu besar diganti dengan ukuran string, batas atas yang lebih kecil dari batas bawah mengembalikan string kosong."
Wooble
2
@Wooble itulah jawaban sebenarnya
jondavidjohn
2
@Wooble Dan apakah Anda tahu mengapa seperti ini? Terimakasih atas klarifikasi Anda.
ijverig
Mengapa? Anda harus bertanya kepada Guido, tapi saya pikir itu elegan untuk dapat mengasumsikan irisan selalu jenis urutan yang sama dengan urutan aslinya, saya sendiri.
Wooble
1
@ Lapinot ya saya telah menulis kode yang bergantung pada perilaku ini. Sayangnya saya tidak dapat mengingat kode tepatnya jadi saya tidak dapat memberi tahu Anda alasannya. Mungkin ada hubungannya dengan substring; mendapatkan string kosong terkadang bisa menjadi apa yang Anda inginkan.
Markus Tebusan

Jawaban:

69

Kamu benar! 'example'[3:4]dan'example'[3] pada dasarnya berbeda, dan memotong di luar batas suatu urutan (setidaknya untuk bawaan) tidak menyebabkan kesalahan.

Ini mungkin mengejutkan pada awalnya, tetapi masuk akal jika Anda memikirkannya. Pengindeksan mengembalikan satu item, tetapi mengiris mengembalikan item berikutnya. Jadi, saat Anda mencoba mengindeks nilai yang tidak ada, tidak ada yang dikembalikan. Namun saat Anda mengiris urutan di luar batas, Anda masih dapat mengembalikan urutan kosong.

Bagian yang membingungkan di sini adalah string berperilaku sedikit berbeda dari daftar. Lihat apa yang terjadi jika Anda melakukan hal yang sama pada daftar:

>>> [0, 1, 2, 3, 4, 5][3]
3
>>> [0, 1, 2, 3, 4, 5][3:4]
[3]

Di sini perbedaannya terlihat jelas. Dalam kasus string, hasilnya tampak identik karena dalam Python, tidak ada karakter individu di luar string. Satu karakter hanyalah string 1 karakter.

(Untuk semantik yang tepat dari mengiris di luar rentang urutan, lihat jawaban mgilson .)

pengirim
sumber
1
Indeks di luar jangkauan bisa saja kembali Nonedaripada membuat kesalahan - itu adalah konvensi Python biasa ketika Anda tidak memiliki apa pun untuk dikembalikan.
Mark Ransom
8
@MarkRansom, itu benar; tetapi mengembalikan Nonedalam kasus ini akan membuat lebih sulit untuk membedakan antara indeks di luar batas dan Nonenilai di dalam daftar. Tetapi bahkan jika ada solusi untuk itu, tetap jelas bagi saya bahwa mengembalikan urutan kosong adalah hal yang benar untuk dilakukan ketika diberi potongan di luar batas. Ini analog dengan melakukan penyatuan dua set yang terputus-putus.
pengirim
Hanya untuk memperjelas, saya tidak mengatakan Anda salah. Saya memahami maksud Anda tentang Nonenilai dalam daftar.
Mark Ransom
1
@ MarkRansom, saya tahu - maaf jika saya terdengar defensif. Sungguh saya hanya ingin alasan untuk merujuk ke teori himpunan :).
pengirim
4
Ah, kecuali saya mengatakan "serikat" bukannya "persimpangan".
pengirim
33

Demi menambahkan jawaban yang mengarah ke bagian yang kuat dalam dokumentasi :

Diberikan ekspresi irisan seperti s[i:j:k],

Irisan s dari i ke j dengan langkah k didefinisikan sebagai urutan item dengan indeks x = i + n*ksedemikian rupa 0 <= n < (j-i)/k. Dengan kata lain, indeks yang i, i+k, i+2*k, i+3*kdan sebagainya, berhenti ketika j tercapai (tetapi tidak pernah termasuk j ). Jika k positif, i dan j direduksi menjadi len(s)jika lebih besar

jika Anda menulis s[999:9999], python kembali s[len(s):len(s)]sejak len(s) < 999dan langkah Anda positif ( 1- default).

mgilson.dll
sumber
Agaknya kapan kpositif, idan jjuga meningkat menjadi -len(s)saat mereka lebih rendah? misalnyas = 'bac'; s[-100:2] == s[-len(s):2]
Chris_Rands
@Chris_Rands Ketika kpositif, Python akan menskalakan idan jagar sesuai dengan batas urutan. Dalam contoh Anda, s[-100:2] == s[0:2]( == s[-len(s):2], omong-omong). Demikian pula s[-100:100] == s[0:2].
tylerc0816
Terima kasih banyak. Ini adalah tanggapan yang lebih baik untuk komentar @ speedplane di atas.
senderle
8

Mengiris tidak dibatasi oleh tipe bawaan. Dan meskipun kedua contoh Anda tampaknya memiliki hasil yang sama, cara kerjanya berbeda; cobalah dengan daftar sebagai gantinya.

Ignacio Vazquez-Abrams
sumber