Soru Python'un dilim gösterimini anlama


Python'un dilim notasyonunda iyi bir açıklamaya ihtiyacım var (referanslar bir artıdır).

Bana göre, bu gösterim birazcık toplanmalı.

Son derece güçlü görünüyor, ama kafamı tam olarak bulamadım.


2300
2018-02-03 22:31


Menşei




Cevaplar:


Gerçekten çok basit:

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

Ayrıca var step Yukarıdakilerden herhangi biri ile kullanılabilen değer:

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

Hatırlanması gereken önemli nokta, :end değer, ilk değeri temsil eder. değil seçilen dilimde. Yani, fark end ve start seçilen eleman sayısıdır (eğer step 1, varsayılan).

Diğer özellik şu ki start veya end olabilir negatif sayı, yani başlangıç ​​yerine dizinin sonuna kadar sayılır. Yani:

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

Benzer şekilde, step negatif bir sayı olabilir:

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, sorduğunuzdan daha az ürün varsa, programcıya iyi gelir. Örneğin, eğer a[:-2] ve a sadece bir öğe içerir, bir hata yerine boş bir liste alırsınız. Bazen hatayı tercih ederdiniz, bu yüzden bunun olabileceğinin farkında olmalısınız.


3113
2018-02-03 22:48



Dilimli yerleşik türleri bir kopyasını döndürür, ancak bu evrensel değildir. Özellikle, NumPy dizileri dilimleme Belleği orijinal ile paylaşan bir görünüm döndürür. - Beni Cherniavsky-Paskin
Bunu ne yapardı? [::-2]  Denedim ama anlamıyorum. Örneğin bu listeyle a = ['1', '2', '3', '4', '5'] . - RodriKing


Python öğreticisi Bu konuda konuşuyor (dilimleme hakkında kısma gelene kadar biraz aşağı kaydırın).

ASCII art diyagramı, dilimlerin nasıl çalıştığını hatırlamak için de faydalıdır:

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

Dilimlerin nasıl çalıştığını hatırlamanın bir yolu, endeksleri işaret etmek olarak düşünmektir. arasında karakterleri, ilk karakterin sol kenarı ile 0 olarak numaralandırıldı. Ardından bir dizenin son karakterinin sağ kenarı n karakter dizini var n.


396
2018-02-03 22:49



Negatif basamaklı dilimler için, bu ASCII sanatını kafa karıştırıcı buluyorum ve -6 dan beri 'ApleH'[:-6:-1] geçerli bir dilimdir ve kullanmaktan farklıdır -5 - Chris_Rands
"Dilimlerin nasıl çalıştığını hatırlamanın bir yolu da, karakterleri işaret etmek için endeksleri düşünmek" - bu konuda düşünmenin harika bir yolu. - jusopi


Dilbilgisi tarafından izin verilen olanakların numaralandırılması:

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

Tabi eğer (high-low)%stride != 0sonra bitim noktası biraz daha düşük olacak high-1.

Eğer stride negatiftir, aşağı doğru saydığımızdan sipariş biraz değiştirilir:

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

Genişletilmiş dilimleme (virgüller ve elipslerle) çoğunlukla sadece özel veri yapılarıyla (Numpy gibi) kullanılır; Temel diziler onları desteklemez.

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



garip bir şey olur mu stride gibi negatif [::-1]? - Charlie Parker
@CharlieParker Ne zaman strike negatiftir high için low. - ephemient
Aslında hala dışarıda bir şey kalmıştır. 'apple' yazıyorsam [4: -4: -1] 'elp' alıyorum, python -4'ü 1'e çeviriyordur belki? - liyuan


Yukarıdaki yanıtlar, dilim atamalarını tartışmıyor:

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

Bu ayrıca dilimleme ve indeksleme arasındaki farkı açıklığa kavuşturabilir.


199
2018-01-18 21:37



ikinci olanı açıklayabilir misin? - chandresh


Python'un dilim gösterimini açıklar.

Kısacası, kolonlar (:) alt simge gösterimisubscriptable[subscriptarg]) isteğe bağlı argümanlar olan dilim notasyonu yapmak start, stop, step:

sliceable[start:stop:step]

Python dilimleme, verilerinizin bölümlerine yöntemsel olarak erişmek için hesaplama açısından hızlı bir yoldur. Benim düşünceme göre, bir ara Python programcısı bile olmak için, aşina olmanın gerekli olduğu dilin bir yönü.

Önemli Tanımlar

Başlamak için birkaç terim tanımlayalım:

başla: Dilimin başlangıç ​​indeksi ile aynı değilse, bu endekste öğeyi içerecektir durdurmakvarsayılan olarak 0'a, yani ilk indekse. Eğer negatifse, başlamak demektir n sonundan öğeler.

durdurmak: dilimin bitiş indeksi, bunu yapar değil Bu endekste bulunan elemanı, dilimlenen sıranın uzunluğunu, yani sonuna kadar ve sonuna kadar içerir.

adım: indeksin arttığı miktar, varsayılanı 1'dir. Eğer negatifse, tersi şekilde yinelenen üzerinde dilimliyorsunuz demektir.

Dizin Oluşturma Nasıl Çalışır?

Bu pozitif veya negatif sayılardan herhangi birini yapabilirsiniz. Pozitif sayıların anlamı basittir, fakat negatif sayılar için, Python'daki indeksler gibi, geriye doğru geriye doğru sayılırsınız. başla ve durdurmakve adım, sadece endeksini azaltırsın. Bu örnek dokümanın öğreticisindenancak her dizinin hangi sırayla başvurduğunu göstermek için biraz değiştirdim:

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

Dilimleme Nasıl Çalışır?

Dilim gösterimini, onu destekleyen bir sekansla kullanmak için, sekansı takip eden köşeli parantez içinde en az bir kolon eklemeniz gerekir. uygulamak __getitem__ Python veri modeline göre dizinin yöntemi.)

Dilim notasyonu şöyle çalışır:

sequence[start:stop:step]

Ve bunun için varsayılan değerler olduğunu hatırlayın. başla, durdurmak, ve adımBu yüzden varsayılanlara erişmek için argümanı bırakmanız yeterlidir.

Son dokuz öğeyi bir listeden (veya bir dizeyi destekleyen herhangi bir başka diziden) almak için dilim gösterimi şöyle görünecektir:

my_list[-9:]

Bunu gördüğümde, parantez içindeki kısmı "sondan sonuna kadar 9." olarak okudum. (Aslında, zihinsel olarak "-9," şeklinde kısaltıyorum)

Açıklama:

Tam gösterim

my_list[-9:None:None]

ve varsayılanları (aslında step negatif stopvarsayılan -len(my_list) - 1, yani None durmak için gerçekten sadece son adımın ne kadar sürdüğü anlamına gelir):

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

kolon, :Python'a ona bir dilim ve normal bir dizin vermediğini söyleyen şey. Bu yüzden Python 2'de listelerin sığ bir kopyasını oluşturmanın deyimsel yolu

list_copy = sequence[:]

Ve onları temizlemek:

del my_list[:]

(Python 3 bir alır list.copy ve list.clear yöntem.)

Ne zaman step negatiftir, varsayılanlar start ve stop değişiklik

Varsayılan olarak, step argüman boş (veya None), atandı +1.

Ancak negatif bir tam sayıya geçebilir ve liste (veya diğer standart dilimleyiciler) en başından sonuna kadar dilimlenir.

Bu nedenle, negatif bir dilim varsayılanları değiştirecek start ve stop!

Bunu kaynakta onaylamak

Kullanıcıları kaynağın yanı sıra belgeleri de okumaları için teşvik ediyorum. dilim nesneleri için kaynak kodu ve bu mantık burada bulunur. Önce belirledik eğer step negatiftir:

 step_is_negative = step_sign < 0;

Eğer öyleyse, alt sınır -1  Başlangıçta dahil olmak üzere tüm yol boyunca dilimlemek anlamına gelir ve üst sınır, eksi 1'dir, yani sonunda başlıyoruz. (Bunun semantik olduğunu unutmayın. -1 olduğu farklı bir -1 Kullanıcıların son öğeyi belirten Python dizinlerini geçirebileceğini.)

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

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

Aksi takdirde step pozitiftir ve alt sınır, dilimlenmiş listenin uzunluğuna ve üst sınıra (ki buna dahil ancak dahil değil) katılacaktır.

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

Ardından, varsayılanları start ve stop - varsayılan o zaman start ne zaman üst sınır olarak hesaplanır step negatiftir:

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

ve stopalt sınır:

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

Dilimlerinize açıklayıcı bir isim verin!

Dilimin dilimlenmesini oluşturmaktan ayırmak yararlı olabilir. list.__getitem__ yöntem (köşeli parantez böyle yapar). Yeni olmasanız bile, kodunuzu daha okunabilir kılar, böylece kodunuzu okuması gereken diğer kişiler, ne yaptığınızı daha kolay anlayabilir.

Ancak, yalnızca bir değişkene iki nokta ile ayrılmış bazı tam sayıları atayamazsınız. Dilim nesnesini kullanmanız gerekir:

last_nine_slice = slice(-9, None)

İkinci argüman, None, gereklidir, böylece ilk argüman olarak yorumlanır start tartışma aksi halde olurdu stop tartışma.

Daha sonra dilim nesnesini dizinize geçirebilirsiniz:

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

Aralığın da dilimleri alması ilginç:

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

Bellek ile ilgili konular:

Python listelerinin dilimleri bellekte yeni nesneler oluşturduğundan, dikkat edilmesi gereken diğer önemli bir işlev itertools.islice. Genellikle bir dilim üzerinde yinelemek isteyeceksiniz, sadece bellekte statik olarak oluşturulmuş değil. islice bunun için mükemmel. Bir uyarı, olumsuz argümanları desteklemiyor start, stopveya stepYani, eğer bir sorun varsa, endeksleri hesaplamanız veya itebilirliği önceden tersine çevirmeniz gerekebilir.

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

ve şimdi:

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

Liste dilimlerinin bir kopya oluşturması, listelerin kendilerinin bir özelliği. Bir Pandas DataFrame gibi gelişmiş nesneleri dilimliyorsanız, bir kopyasını değil, orijinali görüntüleyebilir.


186
2017-07-12 13:19



Merhaba @ aaronhall, mükemmel yazı! Bu yazıya Orta Python kitabına katkıda bulunmayı düşünür müsün? github.com/yasoob/intermediatePython/issues/153 ? - neowulf33
Sadece bu yazı için çok teşekkür etmek istedim, şimdi bir süre Python yazıyorum ve yine de dilimleme ile her zaman bir hata yaparak ortaya çıkıyorum! - akkatracker
en iyi cevap burada - kskyriacou


Ve dilimleme sözdizimini ilk gördüğümde hemen bana açık olmayan birkaç şey:

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

Sıraları tersine çevirmenin kolay yolu!

Ve eğer, bir sebepten ötürü, ters sıradaki her ikinci maddeyi isterseniz:

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

124
2018-02-03 23:15





Bu harika masayı 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





Python 2.7'de

Python'da Dilimleme

[a:b:c]

len = length of string, tuple or list

c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.

a --  When c is positive or blank, default is 0. When c is negative, default is -1.

b --  When c is positive or blank, default is len. When c is negative, default is -(len+1).

Endeks atamayı anlamak çok önemlidir.

In forward direction, starts at 0 and ends at len-1

In backward direction, starts at -1 and ends at -len

[A: b: c] dediğinizde, c (ileri veya geri) işaretine bağlı olarak, b'de başlayıp (bth dizinindeki eleman hariç) başlayarak söylersiniz. Yukarıdaki endeksleme kuralını kullanın ve yalnızca bu aralıktaki öğeleri bulacağınızı unutmayın:

-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1

Fakat bu aralık her iki yönde de sonsuza kadar devam ediyor:

...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....

Örneğin:

             0    1    2   3    4   5   6   7   8   9   10   11
             a    s    t   r    i   n   g
    -9  -8  -7   -6   -5  -4   -3  -2  -1

Eğer a, b ve c seçiminiz, yukarıdaki a, b, c kurallarını kullanarak geçiş yaparken yukarıdaki aralıklarla çakışmaya izin veriyorsa, ya öğelerle (geçiş sırasında dokunduğunuzda) bir liste alacaksınız ya da boş bir liste alacaksınız.

Son bir şey: a ve b eşitse, boş bir liste de alırsınız:

>>> l1
[2, 3, 4]

>>> l1[:]
[2, 3, 4]

>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]

>>> l1[:-4:-1] # a default is -1
[4, 3, 2]

>>> l1[:-3:-1] # a default is -1
[4, 3]

>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]

>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]


>>> l1[-100:-200:-1] # Interesting
[]

>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]


>>> l1[-1:-1:1]
[]


>>> l1[-1:5:1] # Interesting
[4]


>>> l1[1:-7:1]
[]

>>> l1[1:-7:-1] # Interesting
[3, 2]

>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]

84
2017-10-22 05:33



başka ilginç bir örnek: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]hangi sonuç [9] - Deviacium


Bunu kullandıktan sonra, en basit açıklamanın, bir for döngüsündeki argümanlarla tamamen aynı olduğunun farkına varıyorum.

(from:to:step)

bunların herhangi biri isteğe bağlıdır

(:to:step)
(from::step)
(from:to)

o zaman negatif indeksleme sadece dizginin uzunluğunu anlamak için negatif indekslere eklemenizi gerektirir.

Bu zaten benim için çalışıyor ...


47
2018-02-19 20:52





Nasıl çalıştığını daha kolay hatırlıyorum, o zaman herhangi bir başlangıç ​​/ durdur / adım kombinasyonunu anlayabiliyorum.

Anlaması öğreticidir range() ilk:

def range(start=0, stop, step=1):  # illegal syntax, but that's the effect
    i = start
    while (i < stop if step > 0 else i > stop):
        yield i
        i += step

Den başlamak starttarafından artırma stepulaşma stop. Çok basit.

Olumsuz adım hakkında hatırlanması gereken şey, stop daha yüksek veya daha düşük olsun, daima dışlanan uçtur. Tersi sırayla aynı dilimi istiyorsanız, tersini ayrı ayrı yapmak çok daha temizdir: ör. 'abcde'[1:-2][::-1] Bir char sola, iki sağdan keser, sonra tersine çevirir. (Ayrıca bakınız reversed().)

Sekans dilimleme aynıdır, ilk önce negatif indeksleri normalleştirir ve hiçbir zaman dizinin dışına çıkamaz:

YAPMAK: Aşağıdaki kod, abs (step)> 1 iken "dizinin dışına çıkmayın" hatası veren bir hataya sahipti; ben düşünmek Doğru olması için yamalıyım ama anlamak zor.

def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
    if start is None:
        start = (0 if step > 0 else len(seq)-1)
    elif start < 0:
        start += len(seq)
    if not 0 <= start < len(seq):  # clip if still outside bounds
        start = (0 if step > 0 else len(seq)-1)
    if stop is None:
        stop = (len(seq) if step > 0 else -1)  # really -1, not last element
    elif stop < 0:
        stop += len(seq)
    for i in range(start, stop, step):
        if 0 <= i < len(seq):
            yield seq[i]

Endişelenme is None detaylar - sadece bu ihmali hatırla start ve / veya stop her zaman size tüm sırayı vermek için doğru olanı yapar.

Negatif indekslerin normalleştirilmesi ilk önce bağımsız olarak baştan ve / veya durdurulmasına izin verir: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc' rağmen range(1,-2) == []. Normalleştirme, bazen "modulo uzunluk" olarak düşünülür, ancak uzunluğu bir kez eklediğine dikkat edin: örn. 'abcde'[-53:42] sadece bütün dizedir.


32
2018-03-29 10:15



this_is_how_slicing_works python dilimi ile aynı değildir. ÖRNEĞİN. [0, 1, 2][-5:3:3] python'da [0] alır, ama list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3)) [1] olsun. - Eastsun
@Eastsun Oops, haklısın! Daha net bir durum: range(4)[-200:200:3] == [0, 3] fakat list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. Benim if 0 <= i < len(seq): "dizinin dışına çıkma" yöntemini uygulamak için bir girişimdi, ancak adım> 1 için yanlıştır. Bunu daha sonra tekrar yazacağım (testlerle). - Beni Cherniavsky-Paskin


Ben, "elementler arasındaki bir indeks noktaları" yöntemini kendim düşünürüm, fakat bazen başkalarının bunu elde etmesine yardımcı olan bir şekilde tarif etmenin bir yolu şudur:

mylist[X:Y]

X, istediğiniz ilk öğenin dizinidir.
Y ilk elementin indisidir yapamaz istemek.


31
2018-02-06 21:16