4. 시퀀스 자료형(Sequence Types)
1. 키워드
- 시퀀스 자료형(Sequence Types)
- 인덱스(Index)
- 슬라이스(Slice)
2. 시퀀스 자료형 활용하기
list
,tuple
,range
,str
을 잘 보면, 이들 모두 값이 연속적으로 이어져 있다는 공통점이 있다.- 파이썬에서는 이와 같이 값이 연속적으로 이어진 자료형을 시퀀스 자료형이라고 부른다.
- 이 시퀀스 자료형 중에서
list
,tuple
,range
,str
을 주로 사용하며bytes
,bytearray
라는 자료형도 있다.
3. 시퀀스 자료형의 공통 기능 사용하기
- 시퀀스 자료형으로 만든 객체를 시퀀스 객체라고 하며, 시퀀스 객체에 들어있는 각 값을 요소라고 부른다.
1) 특정 값이 있는지 확인하기
- 다음과 같이 시퀀스 객체 안에 특정 값이 있는지 확인할 수 있다.
- 시퀀스 객체에
in
연산자를 사용했을 때 특정 값이 있으면True
, 없으면False
가 나온다. - 따라서 리스트
a
에30
이 있으므로True
,100
이 없으므로False
가 나온다.
- 반대로
in
앞에not
을 붙이면 특정 값이 없는지 확인한다.
- 이렇게
not in
은 특정 값이 없으면True
, 있으면False
가 나온다.
- 물론 튜플,
range
, 문자열도 같은 방법으로 활용할 수 있다.
2) 시퀀스 객체 연결하기
- 시퀀스 객체는
+
연산자를 사용하여 객체를 서로 연결하여 새 객체를 만들 수 있다.
- 리스트
a
와b
를 더하니 두 리스트가 연결되었다. - 물론 변수를 만들지 않고 리스트 여러 개를 직접 연결해도 상관없다.
- 단, 시퀀스 자료형 중에서
range
는+
연산자로 객체를 연결할 수 없다.
>>> range(0, 10) + range(10, 20) # TypeError: unsupported operand type(s) for +: 'range' and '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, "
와"world!"
를 연결하여"Hello, world!"
가 나왔다. - 파이썬에서 문자열 연결은 여러 가지 결과를 묶어서 한 번에 출력할 때 자주 사용한다.
문자열에 숫자 연결하기
- 다음과 같이
"Hello, "
에10
을 연결해 보자.
- 문자열에 정수를 연결하려고 하면 에러가 발생한다.
- 이 문제를 해결하려면
str
을 사용하여 숫자(정수, 실수)를 문자열로 변환하면 된다.
- 문자열에
+
를 사용할 때는 어떤 형태의 값이든str
을 사용해서 문자열로 맞춰주면 된다.
3) 시퀀스 객체 반복하기
*
연산자는 시퀀스 객체를 특정 횟수만큼 반복하여 새 시퀀스 객체를 만든다.- 이때
0
또는 음수를 곱하면 빈 객체가 나오며 실수는 곱할 수 없다.
- 요소
0
,10
,20
,30
이 들어있는 리스트를 3번 반복해서 새 리스트를 만들었다.
- 앞에서
range
는+
연산자로 객체를 연결할 수 없었다. - 마찬가지로
range
는*
연산자를 사용하여 반복할 수 없다.
- 이때는
range
를 리스트 또는 튜플로 만들어서 반복하면 된다.
>>> 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)
- 문자열은
*
연산자를 사용하여 반복할 수 있다.
4. 시퀀스 객체의 요소 개수 구하기
- 시퀀스 객체의 요소의 개수(길이)를 구할 때는
len
함수를 사용한다.
1) 리스트와 튜플의 요소 개수 구하기
- 다음과 같이 리스트
a
의 요소 개수를 구할 수 있다. - 리스트
a
에는 요소가 10개 들어있으므로len(a)
는10
이 나온다.
- 다음 튜플
b
에는 요소가 5개 들어있으므로len(b)
는5
가 나온다.
2) range
의 숫자 생성 개수 구하기
range
에len
함수를 사용하면 숫자가 생성되는 개수를 구한다.
range(0, 10, 2)
는0
부터10
까지2
씩 증가하므로0
,2
,4
,6
,8
이다.- 따라서
5
가 나온다.
3) 문자열의 길이 구하기
- 문자열도 시퀀스 자료형이므로
len
함수를 사용하면 된다.
len
으로"Hello, world!"
문자열이 들어있는hello
의 길이를 구해 보면13
이 나온다.
- 여기서 문자열의 길이는 공백까지 포함한다.
- 한글 문자열의 길이도 다음과 같이
len
으로 구하면 된다.
"안녕하세요"
는 5글자이므로 길이는5
가 나온다.
UTF-8 문자열의 바이트 수 구하기
- 한글, 한자, 일본어 등은 UTF-8 인코딩으로 저장하는데, 문자열이 차지하는 실제 바이트 수를 구하는 방법은 다음과 같다.
- UTF-8에서 한글 글자 하나는
3
바이트로 표현하므로"안녕하세요"
가 차지하는 실제 바이트 수는15
바이트이다.
5. 인덱스 사용하기
- 시퀀스 객체의 각 요소는 순서가 정해져 있으며, 이 순서를 인덱스라고 부른다.
- 다음과 같이 시퀀스 객체에
[]
(대괄호)를 붙이고[]
안에 각 요소의 인덱스를 지정하면 해당 요소에 접근할 수 있다.
- 시퀀스 객체의 인덱스는 항상 0부터 시작한다.
- 튜플,
range
, 문자열도[]
에 인덱스를 지정하면 해당 요소를 가져올 수 있다.
- 다음은 튜플
b
의 첫 번째 요소를 출력한다.
- 다음은
range
의 세 번째 요소를 출력한다.
- 다음은 문자열
hello
의 여덟 번째 요소를 출력한다.
시퀀스 객체에 인덱스를 지정하지 않으면?
- 시퀀스 객체에 인덱스를 지정하지 않은 상태는 해당 객체 전체를 뜻한다.
- 따라서 다음과 같이 리스트
a
를 출력하면[]
를 포함하여 리스트 전체가 출력된다.
__getitem__
메서드
- 시퀀스 객체에서
[]
(대괄호)를 사용하면 실제로는__getitem__
메서드를 호출하여 요소를 가져온다. - 따라서 다음과 같이
__getitem__
메서드를 직접 호출하여 요소를 가져올 수도 있다.
1) 음수 인덱스 지정하기
- 다음과 같이 인덱스를 음수로 지정할 수 있다.
- 시퀀스 객체에 인덱스를 음수로 지정하면 뒤에서부터 요소에 접근하게 된다.
- 즉,
-1
은 뒤에서 첫 번째,-5
는 뒤에서 다섯 번째 요소이다.
- 리스트
a
의 양수 인덱스와 음수 인덱스를 그림으로 표현하면 다음과 같은 모양이 된다.
- 튜플,
range
, 문자열도 음수 인덱스를 지정하면 뒤에서부터 요소에 접근한다.
- 다음은 튜플
b
의 뒤에서 첫 번째 요소를 출력한다.
- 다음은
range
의 뒤에서 세 번째 요소를 출력한다.
- 다음은 문자열
hello
의 뒤에서 네 번째 요소를 출력한다.
2) 인덱스의 범위를 벗어나면?
- 다음과 같이 리스트를 만든 뒤 범위를 벗어난 인덱스에 접근하면 에러가 발생한다.
- 마찬가지로 튜플,
range
, 문자열도 범위를 벗어난 인덱스를 지정하면IndexError
가 발생한다.
3) 마지막 요소에 접근하기
- 시퀀스 객체에 인덱스를
-1
로 지정하면 뒤에서 첫 번째 즉, 마지막 요소에 접근할 수 있다.
- 또한 다음과 같이
len
함수를 이용하여 마지막 요소에 접근할 수도 있다.
4) 요소에 값 할당하기
- 시퀀스 객체의 요소에 값을 할당하는 방법은 다음과 같다.
- 먼저 리스트부터 요소에 값을 할당해 보자.
>>> a = [0, 0, 0, 0, 0]
>>> 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
a[0] = 38
처럼[]
에 인덱스를 지정한 뒤 값을 할당하면 된다.
- 단, 이때도 다음과 같이 범위를 벗어난 인덱스는 지정할 수 없다.
- 튜플은 안에 저장된 요소를 변경할 수 없기 때문에 다음과 같이 튜플의
[]
에 인덱스를 지정한 뒤 값을 할당하면 에러가 발생한다.
- 마찬가지로
range
와 문자열도 안에 저장된 요소를 변경할 수 없다.
>>> r = range(0, 10, 2)
>>> r[0] = 3 # TypeError: 'range' object does not support item assignment
>>> hello = "Hello, world!"
>>> hello[0] = "A" # TypeError: 'str' object does not support item assignment
- 즉, 시퀀스 자료형 중에서 튜플,
range
, 문자열은 읽기 전용이다.
5) del
로 요소 삭제하기
- 요소 삭제는 다음과 같이
del
뒤에 삭제할 요소를 지정해 주면 된다.
- 먼저 리스트부터 저장된 요소를 삭제해 보자.
- 마찬가지로 리스트와는 달리 튜플,
range
, 문자열은 요소를 삭제할 수 없다.
>>> b = (38, 21, 53, 62, 19)
>>> del b[2] # TypeError: 'tuple' object doesn't support item deletion
>>> r = range(0, 10, 2)
>>> del r[2] # TypeError: 'range' object doesn't support item deletion
>>> hello = "Hello, world!"
>>> del hello[2] # TypeError: 'str' object doesn't support item deletion
6. 슬라이스 사용하기
- 시퀀스 자료형은 슬라이스라는 기능을 자주 사용한다.
- 슬라이스는 무엇인가의 일부를 잘라낸다는 뜻인데, 시퀀스 슬라이스도 말 그대로 시퀀스 객체의 일부를 잘라낸다.
- 다음은 리스트의 일부를 잘라서 새 리스트를 만드는 것이다.
[]
안에 시작 인덱스와 끝 인덱스를 지정하면 해당 범위의 리스트를 잘라서 가져올 수 있다.- 여기서 주의할 점이 있는데, 끝 인덱스는 가져오려는 범위에 포함되지 않는다.
- 따라서 끝 인덱스는 실제로 가져오려는 인덱스보다
1
을 더 크게 지정해야 한다.
- 예를 들어 요소가 10개 들어있는 리스트를 처음부터 끝까지 가져오려면
[0:9]
가 아닌[0:10]
이어야 한다.
1) 리스트의 중간 부분 가져오기
- 다음과 같이 리스트의 중간 부분을 가져올 수 있다.
- 또한 슬라이스는
a[4:-1]
과 같이 음수를 인덱스로 지정할 수도 있다.
2) 인덱스 증가폭 사용하기
- 슬라이스는 인덱스의 증가폭을 지정하여 범위 내에서 인덱스를 건너뛰며 요소를 가져올 수 있다.
- 다음과 같이 인덱스를
3
씩 증가시키면서 요소를 가져올 수 있다.
- 여기서 주의할 점은 인덱스의 증가폭이지 요소의 값 증가폭이 아니라는 점이다.
- 인덱스 증가폭을 지정하더라도 가져오려는 인덱스를 넘어설 수 없다는 점을 기억해야 한다.
- 하지만 만약 다음과 같이
끝 인덱스 - 1
과증가한 인덱스
가 일치한다면, 해당 요소까지 가져올 수 있다.
3) 인덱스 생략하기
- 슬라이스를 사용할 때 시작 인덱스와 끝 인덱스를 생략할 수도 있다.
- 인덱스를 생략하는 방법은 시퀀스 객체의 길이를 몰라도 되기 때문에 자주 쓰이는 방식이다.
- 주로 시퀀스 객체의 마지막 일부분만 출력할 때 사용한다.
- 다음과 같이 시작 인덱스를 생략하면서 슬라이스를 사용할 수 있다.
- 그리고 다음과 같이 끝 인덱스를 생략하면서 슬라이스를 사용할 수 있다.
- 또는, 다음과 같이 시작 인덱스와 끝 인덱스를 둘 다 생략하면서 슬라이스를 사용할 수 있다.
4) 인덱스를 생략하면서 증가폭 사용하기
- 다음과 같이 시작 인덱스를 생략하면서 인덱스 증가폭을 지정할 수 있다.
- 그리고 다음과 같이 끝 인덱스를 생략하면서 인덱스 증가폭을 지정할 수 있다.
- 또는, 다음과 같이 시작 인덱스와 끝 인덱스를 둘 다 생략하면서 인덱스 증가폭을 지정할 수 있다.
- 마지막으로, 시작 인덱스, 끝 인덱스, 인덱스 증가폭을 모두 생략할 수도 있다.
- 그냥 리스트 전체를 가져오는 것이므로
a[:]
와a[::]
는 결과가 같다.
슬라이스의 인덱스 증가폭을 음수로 지정하면?
- 슬라이스를 사용할 때 인덱스 증가폭을 음수로 지정하면 요소를 뒤에서부터 가져올 수 있다.
- 다음과 같이 리스트
a
에서 인덱스5
부터2
까지1
씩 감소시키면서 요소를 가져올 수 있다.
- 여기서 주의할 점은 인덱스가 감소하므로 끝 인덱스보다 시작 인덱스를 더 크게 지정해야 한다는 점이다.
- 그리고 끝 인덱슨느 가져오려는 범위에 포함되지 않는다.
- 그리고 다음과 같이 시작 인덱스와 끝 인덱스를 생략하면서 인덱스 증가폭을
-1
로 지정하면 리스트를 반대로 뒤집는 것과 같다.
- 이 방법은 리스트뿐만 아니라 모든 시퀀스 객체에 사용할 수 있다.
slice
객체 사용하기
- 파이썬에서는
slice
객체를 사용하여 시퀀스 객체(시퀀스 자료형으로 만든 변수)를 잘라낼 수도 있다.
슬라이스객체 = slice(끝인덱스)
슬라이스객체 = slice(시작인덱스, 끝인덱스)
슬라이스객체 = slice(시작인덱스, 끝인덱스, 인덱스증가폭)
시퀀스객체[슬라이스객체]
시퀀스객체.__getitem__(슬라이스객체)
- 다음과 같이 시퀀스 객체의
[]
(대괄호) 또는__getitem__
메서드에slice
객체를 넣어주면 지정된 범위만큼 잘라내서 새 객체를 만든다.
>>> range(10)[slice(4, 7, 2)]
range(4, 7, 2)
>>> range(10).__getitem__(slice(4, 7, 2))
range(4, 7, 2)
- 물론
slice
객체를 하나만 만든 뒤 여러 시퀀스 객체에 사용하는 방법도 가능하다.
5) 슬라이스에 요소 할당하기
- 시퀀스 객체는 슬라이스로 범위를 지정하여 여러 요소에 값을 할당할 수 있다.
- 먼저 리스트를 만든 뒤 특정 범위의 요소에 값을 할당해 보자.
>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:5] = ["a", "b", "c"]
>>> a
[0, 10, 'a', 'b', 'c', 50, 60, 70, 80, 90]
- 이렇게 범위를 지정해서 요소를 할당했을 경우에는 원래 있던 리스트가 변경되며 새 리스트는 생성되지 않는다.
a[2:5] = ["a", "b", "c"]
는 슬라이스 범위와 할당할 리스트의 요소 개수를 정확히 맞추었지만, 사실 개수를 맞추지 않아도 상관없다.
- 다음과 같이 요소 개수를 맞추지 않아도 알아서 할당되며, 만약 할당할 요소 개수가 적으면 그만큼 리스트의 요소 개수도 줄어든다.
>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:5] = ["a"]
>>> a
[0, 10, 'a', 50, 60, 70, 80, 90]
- 반면 할당할 요소 개수가 많으면 그만큼 리스트의 요소 개수도 늘어난다.
>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:5] = ["a", "b", "c", "d", "e"]
>>> a
[0, 10, 'a', 'b', 'c', 'd', 'e', 50, 60, 70, 80, 90]
- 또한 다음과 같이 인덱스 증가폭을 지정하여 인덱스를 건너뛰면서 할당할 수 있다.
>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:8:2] = ["a", "b", "c"]
>>> a
[0, 10, 'a', 30, 'b', 50, 'c', 70, 80, 90]
- 단, 인덱스 증가폭을 지정했을 때는 슬라이스 범위의 요소 개수와 할당할 요소 개수가 정확히 일치해야 한다.
>>> a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a[2:8:2] = ["a", "b"] # ValueError: attempt to assign sequence of size 2 to extended slice of size 3
- 당연하게도 튜플,
range
, 문자열은 슬라이스 범위를 지정하더라도 요소를 할당할 수 없다.
>>> b = (0, 10, 20, 30, 40, 50, 60, 70, 80, 90)
>>> b[2:5] = ("a", "b", "c") # TypeError: 'tuple' object does not support item assignment
>>> r = range(10)
>>> r[2:5] = range(0, 3) # TypeError: 'range' object does not support item assignment
>>> hello = "Hello, world!"
>>> hello[7:13] = "Python" # TypeError: 'str' object does not support item assignment
6) del
로 슬라이스 삭제하기
- 슬라이스 삭제는 다음과 같이
del
뒤에 삭제할 범위를 지정해 주면 된다.
- 다음은 리스트의 인덱스 2부터 4까지 요소를 삭제한다.
del
로 요소를 삭제하면 원래 있던 리스트가 변경되며 새 리스트는 생성되지 않는다.
- 다음과 같이 인덱스 증가폭을 지정하여 삭제할 수도 있다.
- 마찬가지로 튜플,
range
, 문자열은del
로 삭제할 수 없다.