[python] 슬라이스 표기법 이해

파이썬의 슬라이스 표기법에 대한 좋은 설명 (참조는 플러스입니다)이 필요합니다.

나 에게이 표기법은 약간의 픽업이 필요합니다.

그것은 매우 강력 해 보이지만, 나는 그 주위에 내 머리를 갖지 못했습니다.



답변

정말 간단합니다.

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

step값 중 하나와 함께 사용할 수있는 값 도 있습니다.

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

기억해야 할 핵심은 :stop값 이 선택한 슬라이스에 없는 첫 번째 값을 나타냅니다 . 따라서, 차이 stopstart(만약 선택된 소자의 수는 step1, 기본값).

다른 특징이다 start또는 stop수있다 네거티브 대신 초기 배열의 끝에서부터 카운트 수단 번호. 그래서:

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

마찬가지로 step음수 일 수 있습니다.

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

파이썬은 당신이 요구하는 것보다 적은 수의 아이템이 있다면 프로그래머에게 친절합니다. 당신이 요구하는 경우 예를 들어, a[:-2]그리고 a단 하나 개의 요소를 포함, 당신은 빈리스트 대신 오류가 발생합니다. 때로는 오류를 선호하기 때문에 이러한 상황이 발생할 수 있음을 알고 있어야합니다.

의 관계 slice()객체

슬라이싱 연산자 []는 실제로 위의 코드 slice()에서 :표기법 (에서만 사용됨)을 사용하는 객체 와 함께 사용 됩니다 [].

a[start:stop:step]

다음과 같습니다.

a[slice(start, stop, step)]

슬라이스 객체는 또한 인수 개수에 따라 약간 다르게 다르게 작동합니다 range(). 즉 둘 다 slice(stop)와 비슷하며 slice(start, stop[, step])지원됩니다. 주어진 인수의 지정을 건너 뛰려면을 사용할 수 있습니다 None. 예를 들어 a[start:]a[slice(start, None)]거나 a[::-1]같습니다 a[slice(None, None, -1)].

:기반 표기법은 간단한 슬라이싱에 매우 도움이 되지만, slice()객체를 명시 적으로 사용 하면 프로그래밍 방식으로 슬라이싱을 생성 할 수 있습니다.


답변

그만큼 파이썬 튜토리얼 그것에 대해 이야기 (약간 아래로 스크롤 당신은 슬라이스에 대한 부분에 도달 할 때까지).

ASCII 아트 다이어그램은 슬라이스의 작동 방식을 기억하는 데에도 도움이됩니다.

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

슬라이스의 작동 방식을 기억하는 한 가지 방법 은 첫 번째 문자의 왼쪽 가장자리가 0 인 인덱스를 문자 사이 를 가리키는 것으로 생각하는 것입니다. 그런 다음 n 개의 문자열 문자열의 마지막 문자의 오른쪽 가장자리 에는 인덱스 n이 있습니다.


답변

문법에 의해 허용되는 가능성을 열거 :

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

물론 만약 그렇다면 (high-low)%stride != 0, 종말점은high-1 입니다.

stride음수 인 경우 , 카운트 다운 이후 순서가 약간 변경됩니다.

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

확장 슬라이싱 (쉼표와 타원 포함)은 대부분 특수 데이터 구조 (예 : NumPy)에서만 사용됩니다. 기본 시퀀스는이를 지원하지 않습니다.

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


답변

위의 답변은 슬라이스 할당에 대해 설명하지 않습니다. 슬라이스 할당을 이해하려면 ASCII 아트에 다른 개념을 추가하면 도움이됩니다.

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

>>> p = ['P','y','t','h','o','n']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
 'P'
>>> p[5]
 'n'

# Slicing gives lists
>>> p[0:1]
 ['P']
>>> p[0:2]
 ['P','y']

하나의 휴리스틱은 0에서 n까지의 슬라이스에 대해 “0은 시작이며 처음부터 시작하여 목록에서 n 개의 항목을 가져옵니다”라고 생각합니다.

>>> p[5] # the last of six items, indexed from zero
 'n'
>>> p[0:5] # does NOT include the last item!
 ['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
 ['P','y','t','h','o','n']

또 다른 휴리스틱은 “어느 슬라이스 든 시작을 0으로 바꾸고 이전 휴리스틱을 적용하여 목록의 끝을 얻은 다음 첫 번째 숫자를 다시 계산하여 처음부터 항목을 잘라냅니다”입니다.

>>> p[0:4] # Start at the beginning and count out 4 items
 ['P','y','t','h']
>>> p[1:4] # Take one item off the front
 ['y','t','h']
>>> p[2:4] # Take two items off the front
 ['t','h']
# etc.

슬라이스 할당의 첫 번째 규칙은 슬라이싱 이 목록을 반환 하므로 슬라이스 할당 에는 목록 (또는 다른 반복 가능)이 필요하다는 것입니다.

>>> p[2:3]
 ['t']
>>> p[2:3] = ['T']
>>> p
 ['P','y','T','h','o','n']
>>> p[2:3] = 't'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable

위에서 볼 수있는 슬라이스 할당의 두 번째 규칙은 슬라이스 인덱싱으로 목록의 모든 부분이 반환된다는 것입니다.

>>> p[2:4]
 ['T','h']
>>> p[2:4] = ['t','r']
>>> p
 ['P','y','t','r','o','n']

슬라이스 할당의 세 번째 규칙은 할당 된 목록 (반복 가능)의 길이가 동일하지 않아도된다는 것입니다. 인덱싱 된 슬라이스는 단순히 슬라이스되고 할당 된 모든 항목으로 일괄 교체됩니다.

>>> p = ['P','y','t','h','o','n'] # Start over
>>> p[2:4] = ['s','p','a','m']
>>> p
 ['P','y','s','p','a','m','o','n']

가장 까다로운 부분은 빈 조각에 할당하는 것입니다. 휴리스틱 1과 2를 사용 하면 빈 조각을 색인화 하는 것이 쉽습니다 .

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []

그리고 당신이 그것을 본 후에, 빈 슬라이스에 슬라이스 할당도 의미가 있습니다.

>>> p = ['P','y','t','h','o','n']
>>> p[2:4] = ['x','y'] # Assigned list is same length as slice
>>> p
 ['P','y','x','y','o','n'] # Result is same length
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # Assigned list is longer than slice
>>> p
 ['P','y','t','x','y','o','n'] # The result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
 ['P','y','t','h','x','y','o','n'] # The result is longer still

슬라이스의 두 번째 숫자 (4)를 변경하지 않기 때문에 빈 슬라이스에 할당 할 때에도 삽입 된 항목은 항상 ‘o’에 대해 쌓입니다. 따라서 빈 슬라이스 할당 위치는 비어 있지 않은 슬라이스 할당 위치의 논리적 확장입니다.

약간 백업하면 슬라이스 시작 카운트 업을 계속 진행하면 어떻게됩니까?

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []

슬라이싱을 사용하면 완료되면 완료됩니다. 뒤로 자르기 시작하지 않습니다. 파이썬에서는 음수를 사용하여 명시 적으로 요청하지 않는 한 음수 보폭을 얻지 못합니다.

>>> p[5:3:-1]
 ['n','o']

“한 번 완료하면 완료”규칙에 이상한 결과가 있습니다.

>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []
>>> p[6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

사실, 인덱싱과 비교하여 파이썬 슬라이싱은 기이하게 오류를 방지합니다.

>>> p[100:200]
 []
>>> p[int(2e99):int(1e99)]
 []

때로는 유용 할 수 있지만 다소 이상한 동작이 발생할 수도 있습니다.

>>> p
 ['P', 'y', 't', 'h', 'o', 'n']
>>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
>>> p
 ['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']

응용 프로그램에 따라, 당신이 원하는 것이거나 아닐 수도 있습니다!


아래는 원래 답변의 텍스트입니다. 많은 사람들에게 유용했기 때문에 삭제하고 싶지 않았습니다.

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

또한 슬라이싱과 인덱싱의 차이점을 명확히 할 수 있습니다.


답변

파이썬의 슬라이스 표기법 설명

즉, 콜론 ( :첨자 표기법) ( subscriptable[subscriptarg]) 메이크업 슬라이스 표기법 – 옵션 인수가, start, stop, step:

sliceable[start:stop:step]

Python 슬라이싱은 계산적으로 데이터의 일부에 체계적으로 액세스하는 방법입니다. 제 생각에는 중급 파이썬 프로그래머가 되려면 익숙해야 할 언어의 한 측면입니다.

중요한 정의

우선 몇 가지 용어를 정의 해 보겠습니다.

start : 슬라이스의 시작 인덱스. stop 과 동일하지 않으면이 인덱스의 요소를 포함합니다 . 기본값은 0, 즉 첫 번째 인덱스입니다. 음수이면 n끝 부터 항목 을 시작한다는 의미 입니다.

중지 : 슬라이스의 끝 인덱스, 그렇지 않습니다 .이 인덱스에 요소를 포함 . 기본적으로 슬라이스되는 시퀀스의 길이, 즉 끝까지 포함합니다.

단계 : 인덱스가 증가하는 양의 기본값은 1입니다. 음수이면 iterable에 대해 반대로 자릅니다.

인덱싱 작동 방식

이 양수 또는 음수를 지정할 수 있습니다. 긍정적 인 숫자의 의미는 간단하지만 음수를 들어, 파이썬에서 인덱스처럼, 당신은의 끝에서 거꾸로 계산 시작정지 , 그리고위한 단계 , 당신은 단순히 인덱스를 감소. 이 예제는 문서의 튜토리얼에서 가져온 것이지만 각 인덱스가 참조하는 시퀀스의 항목을 나타내도록 약간 수정했습니다.

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

슬라이싱 작동 방식

슬라이스 표기법을 지원하는 시퀀스와 함께 슬라이스 표기법을 사용하려면 시퀀스 뒤에 오는 대괄호에 콜론을 하나 이상 포함해야합니다 ( 파이썬 데이터 모델에 따라 실제로 시퀀스 __getitem__방법을 구현 함) ).

슬라이스 표기법은 다음과 같이 작동합니다.

sequence[start:stop:step]

그리고 기본값이 있다는 것을 기억하십시오. 시작 , 정지단계 때문에, 기본값에 액세스 할 수 단순히 인수를 생략.

목록에서 마지막 9 개 요소 (또는 문자열과 같이이를 지원하는 다른 시퀀스)를 가져 오는 슬라이스 표기법은 다음과 같습니다.

my_list[-9:]

이것을 볼 때, 괄호 안의 부분을 “끝에서 끝까지 9 번째”로 읽습니다. (실제로, 나는 그것을 정신적으로 “-9, on”으로 축약합니다)

설명:

전체 표기법은

my_list[-9:None:None]

기본값을 대체하려면 (실제로 step음수 인 경우 stop기본값은 -len(my_list) - 1이므로None 정지 정말 그냥 최종 단계가에 소요 중로 이동을 의미) :

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

콜론 , :당신은 그것을 조각이 아닌 일반 인덱스를 제공하고 파이썬을 알 것입니다. 그렇기 때문에 파이썬 2에서 얕은 목록을 만드는 관용적 인 방법은

list_copy = sequence[:]

그리고 그것들을 지우는 것은 다음과 같습니다.

del my_list[:]

(파이썬 3는 list.copylist.clear 메소드를 .)

step부정적인, 기본값을위한입니다startstop 변경

기본적으로 step인수가 비어있는 경우 (또는None )+1 .

그러나 음수를 전달할 수 있으며 목록 (또는 대부분의 다른 표준 슬라 이블)은 처음부터 끝까지 슬라이스됩니다.

따라서 네거티브 슬라이스는 start및에 대한 기본값을 변경합니다stop !에 .

소스에서 이것을 확인

사용자가 문서뿐만 아니라 소스를 읽도록 권장합니다. 슬라이스에 대한 소스 코드는 객체와이 논리는 여기에서 발견된다 . 먼저 step부정적 인지 판단합니다 .

 step_is_negative = step_sign < 0;

그렇다면 하한은 -1 시작 부분을 포함하여 끝까지 슬라이스하고 상한은 길이에서 1을 뺀 값으로 끝에서 시작 함을 의미합니다. (참고 이것의 의미는 -1이다 상이한 A로부터 -1사용자가 마지막 항목을 나타내는 파이썬 인덱스를 통과 할 수있다.)

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

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

그렇지 않으면 step양수이고 하한은 0이되고 상한은 (우리가 포함하지만 포함하지 않는) 슬라이스 된 목록의 길이입니다.

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

그런 다음, 우리의 기본값을 적용해야 start하고 stop– 기본 다음에 대한 start상한으로 할 때 계산 step부정적이다 :

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

그리고 stop는이 하한 :

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

슬라이스에 설명적인 이름을 지정하십시오!

슬라이스를 list.__getitem__메소드에 전달하는 것과 분리하는 것이 분리하는 것이 유용 할 수 있습니다 ( 대괄호가하는 일 ). 새로운 것이 아니더라도 코드를 더 읽기 쉽게 유지하여 코드를 읽어야하는 다른 사람들이 자신이하는 일을 더 쉽게 이해할 수 있도록합니다.

그러나 콜론으로 구분 된 정수를 변수에 지정할 수는 없습니다. 슬라이스 객체를 사용해야합니다.

last_nine_slice = slice(-9, None)

두 번째 인수는 None첫 번째 인수는 것으로 해석 될 수 있도록, 필요한 start인수 그렇지 않으면이 될 것 stop인수 .

그런 다음 슬라이스 객체를 시퀀스에 전달할 수 있습니다.

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

범위에도 조각이 필요하다는 점이 흥미 롭습니다.

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

메모리 고려 사항 :

파이썬 목록 조각은 메모리에 새로운 객체를 생성하기 때문에 알아야 할 또 다른 중요한 기능은입니다 itertools.islice. 일반적으로 메모리에서 정적으로 생성 된 것이 아니라 슬라이스를 반복하는 것이 좋습니다. islice이것에 완벽합니다. 주의해야 할 점은, 그것은 부정적인 인수를 지원하지 않는 start, stop또는 step, 그 문제의 그렇다면 당신이 인덱스를 계산하거나 사전에 반복자를 반전해야 할 수도 있습니다.

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

그리고 지금:

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

목록 조각이 복사본을 만든다는 사실은 목록 자체의 기능입니다. Pandas DataFrame과 같은 고급 개체를 슬라이스하는 경우 복사본이 아니라 원본에서보기를 반환 할 수 있습니다.


답변

그리고 슬라이싱 구문을 처음봤을 때 나에게 분명하지 않은 몇 가지 사항이 있습니다.

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

시퀀스를 바꾸는 쉬운 방법!

그리고 당신이 어떤 이유로 든 역순으로 매 두 번째 항목을 원한다면 :

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


답변

파이썬 2.7에서

파이썬에서 슬라이싱

[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).

인덱스 할당을 이해하는 것이 매우 중요합니다.

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

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

[a : b : c]라고 말하면 c의 부호 (앞뒤로)에 따라 a에서 시작하여 b에서 끝납니다 (b 번째 인덱스의 요소 제외). 위의 색인 규칙을 사용하면이 범위의 요소 만 찾을 수 있습니다.

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

그러나이 범위는 양방향으로 무한대로 계속됩니다.

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

예를 들면 다음과 같습니다.

             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

위의 a, b, c에 대한 규칙을 사용하여 트래버스 할 때 a, b 및 c를 선택하면 위의 범위와 겹칠 수 있습니다.

마지막으로 a와 b가 같으면 빈 목록이 나타납니다.

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