파이썬 | 시퀀스(sequence) 자료형

CHOI·2021년 10월 20일
0

Python

목록 보기
7/33
post-thumbnail

1. 시퀀스 (sequence)

우리가 지금까지 배웠던 리스트, 튜플, 문자열, range 를 자세히 보면 공통점이 있다. 바로 이들 모두 연속적(sequence)으로 되어 있다는 것이다.

Untitled

파이썬에서는 이와 같이 값들이 연속적으로 이어진 자료형을 시퀀스 자료형(sequence types) 이라고 한다.

Untitled

이 시퀀스 자료형 중에는 주로 list, tuple, range, str 을 사용하고 그 외에도 bytes 와 bytearray 가 있다. 이에 대한 내용은 나중에 살펴보자.

시퀀스 자료형의 공통 기능

굳이 우리가 시퀀스 자료형을 따로 나눈 이유는 이들은 공통적인 동작과 기능을 수행할 수 있기 때문이다. 따라서 시퀀스 자료형의 기본적인 사용법을 알면 나중에 어떠한 시퀀스 자료형이 와도 큰 어려움 없이 사용할 수 있다.

Untitled

특정 값이 있는지 확인 ( in , not in )

>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> 5 in a
True
>>> 10 in a
False
>>> 10 not in a
True

in 이라는 것을 사용하면 위와 같이 특정한 값이 시퀀스 자료형안에 있는지 확인할 수 있다. 그에 따른 리턴값은 불로 TureFalse 로 나온다.

또한 not in 을 사용하면 특정 값이 없는지 확인이 가능하다.

>>> 4 in (7,4,6,3)
True
>>> 7 in range(0,10,2)
False
>>> 'p' in 'python'
True

물론 리스트 외에 다른 시퀀스 자료형도 위와 같이 사용할 수 있다.

시퀀스 객체 연결하기

시퀀스 객체는 + 연산자를 사용하여 객체를 연결할 수 있다.

>>> a = 1,2,3
>>> b = [4,5,6]
>>> a + b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "list") to tuple
>>> a + a
(1, 2, 3, 1, 2, 3)
>>> b + b
[4, 5, 6, 4, 5, 6]

Untitled

하지만 같은 자료형끼리만 더할 수 있다. 위의 예제에도 튜플 + 리스트를 하니까 오류가 나오는 것을 볼 수 있다.

또 예외가 하나 더 있는데

>>> range(0, 10) + range(10, 20)
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    range(0, 10) + range(10, 20)
TypeError: unsupported operand type(s) for +: 'range' and 'range'

range + range 는 할 수 없다. 이때는 range 를 튜플이나 리스트로 만들어서 더하면 된다.

>>> list(range(0, 10)) + list(range(10, 20))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> tuple(range(0, 10)) + tuple(range(10, 20))
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

문자열 + 숫자

문자열 + 숫자는 가능할까?

>>> 'hello' + 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

오류가 발생한다. 정수와 문자열을 연결하려고 하니까 오류가 발생하는 것이다. 만약 둘이 연결하고 싶다면 숫자를 문자열로 바꿔주면 된다.

>>> 'hello' + str(5)
'hello5'

이와 같이 str 로 형변환을 해준 다음에 더하면 된다.

시퀀스 객체 반복하기

앞서 [1, 2, 3] + [1, 2, 3] 의 결과는 [1, 2, 3, 1, 2, 3] 이였다. 그렇다면 곱하기를 하면 어떨까?

>>> a = [1,2,3]
>>> a * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

곱한 만큼 반복된 시퀀스가 나온다. (음수나 0을 곱하면 빈문자열이 나오고 실수를 곱할 수는 없다.)

Untitled

앞서 range+ 연산을 사용할 수 없었다. 마찬가지로 * 또한 range 에서는 사용할 수 없다.

>>> range(0, 5, 2) * 3
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    range(0, 5, 2) * 3
TypeError: unsupported operand type(s) for *: 'range' and 'int'

따라서 이를 사용하기 위해서는 아까와 마찬가지로 리스트나 튜플로 바꿔주면 사용이 가능하다.

>>> list(range(0, 5, 2)) * 3
[0, 2, 4, 0, 2, 4, 0, 2, 4]
>>> tuple(range(0, 5, 2)) * 3
(0, 2, 4, 0, 2, 4, 0, 2, 4)

문자열은 * 를 사용할 수 있다.

>>> 'Hello, ' * 3
'Hello, Hello, Hello, '

요소 개수 구하기

>>> a = [10,20,30,40,50]
>>> len(a)
5

Untitled

range 의 숫자 생성 개수 구하기

>>> len(range(0, 10, 2))
5

Untitled

문자열 길이 구하기

>>> hello = 'Hello, world!'
>>> len(hello)
13

Untitled

문자열 길이에는 띄어쓰기도 포함된 길이를 나타낸다.

UTF-8 문자열의 바이트 수 구하기

>>> hello = '안녕하세요'
>>> len(hello.encode('utf-8'))
15

문자열이 차지하는 실제 바이트 수를 구하려면 위와 같이 하면 된다. 한글은 한 글자의 3바이트 이기 때문에 15가 나온 것이다.

참고로 파이썬 3에서는 len 은 문자열의 길이를 리턴하지만 파이썬 2.7에서는 실제 바이트 수를 구해주는 차이점이 있다.

2. 인덱스

-리스트

>>> a = [38, 21, 53, 62, 19]
>>> a[0]    # 리스트의 첫 번째(인덱스 0) 요소 출력
38
>>> a[2]    # 리스트의 세 번째(인덱스 2) 요소 출력
53
>>> a[4]    # 리스트의 다섯 번째(인덱스 4) 요소 출력
19

-튜플

>>> b = (38, 21, 53, 62, 19)
>>> b[0]        # 튜플의 첫 번째(인덱스 0) 요소 출력
38

-range

>>> r = range(0, 10, 2)
>>> r[2]        # range의 세 번째(인덱스 2) 요소 출력
4

-문자열

>>> hello = 'Hello, world!'
>>> hello[7]    # 문자열의 여덟 번째(인덱스 7) 요소 출력
'w'

getitem

>>> a = [38, 21, 53, 62, 19]
>>> a.__getitem__(1)
21

__getitem__ 메서드를 사용하여 요소를 직접 가져올 수도 있다.

음수 인덱스

>>> a = [38, 21, 53, 62, 19]
>>> a[-1]   # 리스트의 뒤에서 첫 번째(인덱스 -1) 요소 출력
19
>>> a[-5]   # 리스트의 뒤에서 다섯 번째(인덱스 -5) 요소 출력
38

인덱스로 음수를 지정하면 뒤에서 부터 요소에 접근하게 된다.

Untitled

마지막 요소에 접근하기

인덱스에 음수 -1 을 사용하면 마지막 요소에 접근이 가능했었다. 그렇다면 다른 방법은 없을까?? len 을 사용하면 된다.

>>> a = [10,20,30,40,50]

다음과 같은 리스트에서 len(a) 는 5가 나올 것이다. 그런데 마지막 요소의 인덱스는 4이기 때문에 len(a) - 1 이다. 따라서 다음과 같이 하면 마지막 요소에 접근이 가능하다.

>>> a[len(a) - 1]
50

요소에 값 할당하기

>>> a = [0, 0, 0, 0, 0]    # 0이 5개 들어있는 리스트
>>> a[0] = 38
>>> a[1] = 21
>>> a[2] = 53
>>> a[3] = 62
>>> a[4] = 19
>>> a
[38, 21, 53, 62, 19]
>>> a[0]
38
>>> a[4]
19

위와 같이 리스트에 값을 다시 할당할 수 있다.

그러나 튜플은 앞서 말했듯이 수정이 불가능하다. 따라서 위와 같이 튜플의 값을 바꾸려고 하면 오류가 발생한다.

요소 삭제하기 ( del )

>>> a = [38, 21, 53, 62, 19]
>>> del a[2]
>>> a
[38, 21, 62, 19]

3. 슬라이스

슬라이스는 말 그대로 무언가 일부를 잘라낸다는 뜻이다.

>>> a
[10, 20, 30, 40, 50]
>>> a[0:3]
[10, 20, 30]

[] 안에 시작 인덱스와 끝 인덱스를 지정하면 해당 범위의 요소들을 가져온다. 여기서 주의할 점은 끝 인덱스 요소는 포함되지 않는다는 것이다. 따라서 끝 인덱스를 실제로 가져오려면 인덱스보다 1을 더 크게 지정해줘야한다.

Untitled

따라서 예를 들어 요소가 10개있는 리스트를 처음부터 끝까지 가져오기 위해서는 [0:9] 가 아니라 [0:10] 으로 슬라이스를 해야 전부 가져올 수 있다는 것이다.

>>> a
[10, 20, 30, 40, 50]
>>> a[1:1] # 인덱스 1부터 0까지 잘라서 새 리스트를 만듦
[]
>>> a[1:2] # 인덱스 1부터 1까지 잘라서 새 리스트를 만듦
[20]

따라서 [1:1] 는 아무것도 못 가져오고 [1:2] 는 인덱스 1 번의 요소만 가져오게 되는 것이다.

음수 인덱스 활용

>>> a = [10,20,30,40,50,60,70,80,90]
>>> a[6:-1]
[70, 80]

앞서 우리가 배운 음수 인덱스를 활용하면 위와 같이 끝에서 두번째 인덱스 까지의 요소를 가져올 수 있다. [6:-1] 이면 6번 인덱스부터 -1번 인덱스까지(포함x) 이기 때문에 실제로 가져오는 요소는 6번 인덱스부터 -2번 인덱스 까지 가져오는 것이다.

Untitled

인덱스 증가폭

지금까지는 지정된 범위의 요소들을 가져왔다. 그러나 슬라이스는 증가폭을 지정하여 가져올수도 있다.

>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:8:3]    # 인덱스 2부터 3씩 증가시키면서 인덱스 7까지 가져옴
[20, 50]

Untitled

인덱스 생략

인덱스를 생략해서 슬라이스를 활용하는 방법도 있다. 시퀀스 객체의 길이를 몰라도 되기 때문에 자주 쓰이는 방식이다. 주로 마지막 일부분만 출력할 때 자주 사용한다.

>>> a
[10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[:7]
[10, 20, 30, 40, 50, 60, 70]
>>> a[7:]
[80, 90]

또는 a[:] 와 같이 시작 인덱스와 끝 인덱스 둘다 생략하면 리스트 전체를 가져온다.

>>> a[:]
[10, 20, 30, 40, 50, 60, 70, 80, 90]

인덱스 생략이 가능하기 때문에 다음과 같은 예제도 가능하다.

>>> a[::2] # 리스트 전체에서 인덱스 0부터 2씩 증가시키면서 요소를 가져옴
[10, 30, 50, 70, 90]

슬라이즈 음수 증가폭

그렇다면 만약에 증가폭을 음수로 지정하면 어떻게 될까?

>>> a
[10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[5:1:-1]
[60, 50, 40, 30]
>>> a[5:1:-2]
[60, 40]

시작 인덱스부터 끝 인덱스까지 감소폭 만큼 감소하면서 가져오는데 끝 인덱스는 포함되지 않고 가져온다.

여기서 주의할 점은 인덱스가 감소하므로 끝 인덱스보다 시작 인덱스가 더 커야 한다는 점이다.

len 응용하기

>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[0:len(a)]    # 시작 인덱스에 0, 끝 인덱스에 len(a) 지정하여 리스트 전체를 가져옴
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[:len(a)]     # 시작 인덱스 생략, 끝 인덱스에 len(a) 지정하여 리스트 전체를 가져옴
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

리스트 a 의 요소의 개수는 10개이다. 따라서 len(a) 는 10이고 즉 a[0:10] 과 같다. 여기서 끝 인덱스를 10으로 지정했는데 끝 인덱스는 포함하지 않고 0부터 9인덱스 까지 출력한다. 그런데 실제 마지막 요소의 인덱스는 9 이기 때문에 전부 출력되는 것이다.

Untitled

slice 객체 사용

파이썬에서는 slice 객체를 사용하여 시퀀스 자료형을 잘라낼 수 있다.

  • slice(끝인덱스)
  • slice(시작인덱스, 끝인덱스)
  • slice(시작인덱스, 끝인덱스, 인덱스증가폭)
>>> range(10)[4:7:2]
range(4, 7, 2)
>>> range(10)[slice(4, 7, 2)]
range(4, 7, 2)
>>> range(10).__getitem__(slice(4, 7, 2))
range(4, 7, 2)
>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> s = slice(4, 7)    # 인덱스 4부터 6까지 자르는 slice 객체 생성
>>> a[s]
[40, 50, 60]
>>> r = range(10)
>>> r[s]
range(4, 7)
>>> hello = 'Hello, world!'
>>> hello[s]
'o, '

슬라이스에 요소 할당

>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:5] = ['a', 'b', 'c']    # 인덱스 2부터 4까지 값 할당
>>> a
[0, 10, 'a', 'b', 'c', 50, 60, 70, 80, 90]

슬라이스를 활용하면 위와 같이 원하는 구간에 요소를 바꿔줄 수 있다.

>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:5] = ['a']    # 인덱스 2부터 4까지에 값 1개를 할당하여 요소의 개수가 줄어듦
>>> a
[0, 10, 'a', 50, 60, 70, 80, 90]

앞선 예제에서는 요소의 개수를 맞춰서 바꿔줬는데 위와 같이 요소의 개수를 맞춰주지 않아도 된다. 만약 할당된 요소의 개수가 적으면 그만큼 리스트의 요소의 개수도 줄어든다.

증가폭도 활용하여 아래와 같이 요소를 할당할 수 있다.

>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:8:2] = ['a', 'b', 'c']    # 인덱스 2부터 2씩 증가시키면서 인덱스 7까지 값 할당
>>> a
[0, 10, 'a', 30, 'b', 50, 'c', 70, 80, 90]

Untitled

del 로 슬라이스 삭제하기

>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> del a[2:5]    # 인덱스 2부터 4까지 요소를 삭제
>>> a
[0, 10, 50, 60, 70, 80, 90]

Untitled

앞서 배운 del 을 사용하여 슬라이스를 삭제할 수 있다.

profile
벨로그보단 티스토리를 사용합니다! https://flight-developer-stroy.tistory.com/

0개의 댓글