Pertanyaan Memahami notasi potongan Python


Saya perlu penjelasan yang baik (referensi adalah nilai tambah) pada notasi slabs Python.

Bagi saya, notasi ini perlu sedikit mengambil.

Kelihatannya sangat kuat, tapi aku belum cukup memikirkannya.


2290
2018-02-03 22:31


asal


Jawaban:


Ini benar-benar sangat sederhana:

a[start:end] # items start through end-1
a[start:]    # items start through the rest of the array
a[:end]      # items from the beginning through end-1
a[:]         # a copy of the whole array

Ada juga yang step nilai, yang dapat digunakan dengan salah satu di atas:

a[start:end:step] # start through not past end, by step

Kunci utama untuk diingat adalah bahwa :end nilai mewakili nilai pertama itu tidak dalam irisan yang dipilih. Jadi, bedanya beween end dan start adalah jumlah elemen yang dipilih (jika step adalah 1, default).

Fitur lainnya adalah itu start atau end mungkin negatif angka, yang berarti menghitung dari akhir array, bukan awal. Begitu:

a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items

Demikian pula, step mungkin angka negatif:

a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed

Python baik kepada programmer jika ada lebih sedikit item dari yang Anda minta. Misalnya, jika Anda meminta a[:-2] dan a hanya berisi satu elemen, Anda mendapatkan daftar kosong, bukan kesalahan. Kadang-kadang Anda lebih suka kesalahan, jadi Anda harus sadar bahwa ini mungkin terjadi.


3094
2018-02-03 22:48



Itu Tutorial Python membicarakannya (gulir ke bawah sedikit sampai Anda mendapatkan bagian tentang mengiris).

Diagram seni ASCII juga membantu untuk mengingat cara kerja irisan:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

Salah satu cara untuk mengingat bagaimana irisan bekerja adalah dengan memikirkan indeks sebagai penunjuk antara karakter, dengan tepi kiri karakter pertama bernomor 0. Kemudian tepi kanan karakter terakhir dari string n karakter memiliki indeks n.


394
2018-02-03 22:49



Menghitung kemungkinan yang diizinkan oleh tata bahasa:

>>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
>>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
>>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
>>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
>>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
>>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
>>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
>>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]

Tentu saja jika (high-low)%stride != 0, maka titik akhirnya akan sedikit lebih rendah daripada high-1.

Jika stride negatif, pemesanan diubah sedikit karena kami menghitung mundur:

>>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
>>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
>>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]

Pengirisan yang diperpanjang (dengan koma dan elips) kebanyakan hanya digunakan oleh struktur data khusus (seperti Numpy); urutan dasar tidak mendukungnya.

>>> class slicee:
...     def __getitem__(self, item):
...         return `item`
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'

310
2018-02-03 23:08



Jawaban di atas tidak membahas pembagian tugas:

>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]

Ini juga dapat memperjelas perbedaan antara pengirisan dan pengindeksan.


199
2018-01-18 21:37



Jelaskan notasi potongan Python

Singkatnya, titik dua (:) dalam notasi subscript (subscriptable[subscriptarg]) membuat notasi slice - yang memiliki argumen opsional, start, stop, step:

sliceable[start:stop:step]

Pengirisan Python adalah cara komputasi cepat untuk mengakses secara metodis bagian-bagian data Anda. Menurut pendapat saya, untuk menjadi programmer Python menengah, itu adalah salah satu aspek dari bahasa yang perlu diketahui.

Definisi Penting

Untuk memulainya, mari kita definisikan beberapa istilah:

mulai: indeks awal dari irisan, itu akan mencakup elemen pada indeks ini kecuali itu sama dengan berhenti, default ke 0, yaitu indeks pertama. Jika negatif, itu berarti memulai n item dari akhir.

berhenti: indeks akhir dari irisan itu tidak termasuk elemen pada indeks ini, default untuk panjang urutan yang diiris, yaitu hingga dan termasuk akhir.

langkah: jumlah di mana indeks meningkat, default ke 1. Jika negatif, Anda mengiris iterable secara terbalik.

Bagaimana Pengindeksan Bekerja

Anda dapat membuat angka positif atau negatif ini. Arti bilangan positif sangat mudah, tetapi untuk bilangan negatif, seperti indeks dengan Python, Anda menghitung mundur dari akhir untuk mulai dan berhenti, dan untuk langkah, Anda hanya mengurangi indeks Anda. Contoh ini dari tutorial dokumentasi, tetapi saya telah sedikit memodifikasi untuk menunjukkan item mana dalam urutan masing-masing referensi indeks:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5 
  -6  -5  -4  -3  -2  -1

Bagaimana Mengiris Pekerjaan

Untuk menggunakan notasi slice dengan urutan yang mendukungnya, Anda harus menyertakan setidaknya satu titik dua dalam tanda kurung siku yang mengikuti urutan (yang sebenarnya terapkan __getitem__ metode urutan, menurut model data Python.)

Slice notation berfungsi seperti ini:

sequence[start:stop:step]

Dan ingat bahwa ada default untuk mulai, berhenti, dan langkah, jadi untuk mengakses default, cukup tinggalkan argumen.

Slice notation untuk mendapatkan sembilan elemen terakhir dari daftar (atau urutan lain yang mendukungnya, seperti string) akan terlihat seperti ini:

my_list[-9:]

Ketika saya melihat ini, saya membaca bagian dalam tanda kurung sebagai "9 dari ujung, sampai akhir." (Sebenarnya, saya menyingkatnya secara mental sebagai "-9, on")

Penjelasan:

Notasi lengkapnya

my_list[-9:None:None]

dan mengganti default (sebenarnya saat step negatif, stopadalah default -len(my_list) - 1, jadi None untuk berhenti benar-benar hanya berarti pergi ke mana saja langkah akhir membawanya ke):

my_list[-9:len(my_list):1]

Itu usus besar, :, adalah apa yang memberitahu Python Anda memberikannya sepotong dan bukan indeks biasa. Itu sebabnya cara idiomatis membuat salinan daftar dangkal dengan Python 2 adalah

list_copy = sequence[:]

Dan membersihkan mereka adalah dengan:

del my_list[:]

(Python 3 mendapat list.copy dan list.clear metode.)

Kapan step negatif, default untuk start dan stop perubahan

Secara default, ketika step argumen kosong (atau None), ditugaskan untuk +1.

Tetapi Anda dapat mengirimkan bilangan bulat negatif, dan daftar (atau sebagian besar dokumen standar lainnya) akan diiris dari ujung ke awal.

Jadi potongan negatif akan mengubah default untuk start dan stop!

Mengkonfirmasi ini di sumbernya

Saya suka mendorong pengguna untuk membaca sumber serta dokumentasi. Itu kode sumber untuk objek slice dan logika ini ditemukan di sini. Pertama kita tentukan jika step negatif:

 step_is_negative = step_sign < 0;

Jika demikian, batas bawahnya -1  artinya kita mengiris sepanjang jalan hingga dan termasuk awal, dan batas atas adalah panjang minus 1, yang berarti kita mulai di bagian akhir. (Perhatikan bahwa semantik ini -1 aku s berbeda dari -1 bahwa pengguna dapat lulus indeks dengan Python menunjukkan item terakhir.)

if (step_is_negative) {
    lower = PyLong_FromLong(-1L);
    if (lower == NULL)
        goto error;

    upper = PyNumber_Add(length, lower);
    if (upper == NULL)
        goto error;
}

Jika tidak step positif, dan batas bawah akan menjadi nol dan batas atas (yang kita naik tetapi tidak termasuk) panjang daftar yang diiris.

else {
    lower = _PyLong_Zero;
    Py_INCREF(lower);
    upper = length;
    Py_INCREF(upper);
}

Kemudian, kami mungkin perlu menerapkan default untuk start dan stop - defaultnya untuk start dihitung sebagai batas atas saat step negatif:

if (self->start == Py_None) {
    start = step_is_negative ? upper : lower;
    Py_INCREF(start);
}

dan stop, batas bawah:

if (self->stop == Py_None) {
    stop = step_is_negative ? lower : upper;
    Py_INCREF(stop);
}

Berikan irisan Anda nama yang deskriptif!

Anda mungkin merasa berguna untuk memisahkan membentuk irisan dari melewatkannya ke list.__getitem__ metode (itulah yang dilakukan kurung persegi). Bahkan jika Anda tidak baru, itu membuat kode Anda lebih mudah dibaca sehingga orang lain yang mungkin harus membaca kode Anda dapat lebih mudah memahami apa yang Anda lakukan.

Namun, Anda tidak dapat hanya menetapkan beberapa bilangan bulat yang dipisahkan oleh titik dua ke variabel. Anda perlu menggunakan objek slice:

last_nine_slice = slice(-9, None)

Argumen kedua, None, diperlukan, sehingga argumen pertama ditafsirkan sebagai start argumen kalau tidak, itu akan menjadi stop argumen.

Anda kemudian dapat meneruskan objek slice ke urutan Anda:

>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Sangat menarik bahwa rentang juga mengambil irisan:

>>> range(100)[last_nine_slice]
range(91, 100)

Pertimbangan Memori:

Karena irisan daftar Python membuat objek baru dalam memori, fungsi penting lainnya yang harus diperhatikan adalah itertools.islice. Biasanya Anda ingin mengulang lebih dari satu irisan, bukan hanya membuatnya secara statis dalam memori. islice sangat cocok untuk ini. Sebuah peringatan, itu tidak mendukung argumen negatif start, stop, atau step, jadi jika itu masalah Anda mungkin perlu menghitung indeks atau membalikkan iterable sebelumnya.

length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)

dan sekarang:

>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Fakta bahwa daftar irisan membuat salinan adalah fitur dari daftar itu sendiri. Jika Anda mengiris objek canggih seperti Pandas DataFrame, itu mungkin mengembalikan tampilan pada aslinya, dan bukan salinannya.


184
2017-07-12 13:19



Dan beberapa hal yang tidak begitu jelas bagi saya ketika saya pertama kali melihat sintaksis pemotongan:

>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]

Cara mudah untuk membalik urutan!

Dan jika Anda menginginkan, untuk beberapa alasan, setiap item kedua dalam urutan terbalik:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]

124
2018-02-03 23:15



Temukan meja besar ini di http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.

Index from rear:    -6  -5  -4  -3  -2  -1      a=[0,1,2,3,4,5]    a[1:]==[1,2,3,4,5]
Index from front:    0   1   2   3   4   5      len(a)==6          a[:5]==[0,1,2,3,4]
                   +---+---+---+---+---+---+    a[0]==0            a[:-2]==[0,1,2,3]
                   | a | b | c | d | e | f |    a[5]==5            a[1:2]==[1]
                   +---+---+---+---+---+---+    a[-1]==5           a[1:-1]==[1,2,3,4]
Slice from front:  :   1   2   3   4   5   :    a[-2]==4
Slice from rear:   :  -5  -4  -3  -2  -1   :
                                                b=a[:]
                                                b==[0,1,2,3,4,5] (shallow copy of a)

84
2017-09-06 06:50