Python
3.2. 리스트
federe
2012. 1. 10. 17:43
리스트 소개
리스트는 파이썬의 핵심 데이터유형입니다. (설마 그럴리는 없겠지만) 리스트에 대한 경험이 비주얼 베이직(Visual Basic)의 배열이나 파워빌더(Powerbuilder)의 데이터스토어일 뿐이라면 파이썬의 리스트에 단단히 대비하세요.
☞ 파이썬의 리스트는 펄(Perl)의 배열과 같습니다. 펄(Perl)에서 배열이 저장된 변수는 언제나 @ 문자로 시작합니다; 파이썬에서 변수는 아무 이름이나 상관없으며 내부적으로 파이썬이 그 데이터유형을 추적관리합니다.
☞ 파이썬의 리스트는 자바(Java)의 배열 그 이상입니다 (물론, 삶에서 정말로 필요한 모든 것이라면 배열처럼 사용할 수 있습니다.). 좀 더 비유를 잘 들자면 ArrayList 클래스가 될 텐데 이 클래스는 어떤 객체도 담을 수 있으며 새로 원소가 추가될 때마다 확장될 수 있습니다.
3.2.1. 리스트 정의하기
예제 3.6. 리스트 정의하기
- >>> li = ['a", "b", "mpilgrim", "z", "example'] ①
- >>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[0] ②
'a'
>>> li[4] ③
'example'
① 먼저, 원소가 다섯 개인 리스트를 정의합니다. 원래의 순서를 유지하고 있음에 주목하세요. 이는 우연이 아닙니다. 리스트는 순서가 있는 집합으로서 각괄호로 둘러싸입니다.
② 리스트는 0-기반 배열처럼 사용할 수 있습니다. 리스트의 첫 요소는 언제나 li[0]입니다.
③ 이 원소 다섯 개짜리 리스트에서 마지막 원소는 li[4]인데 왜냐하면 리스트는 언제나 지표가 0에서부터 시작하기 때문입니다.
예제 3.7. 리스트의 음수 지표
- >>> li
- ['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[-1] ①
'example'
>>> li[-3] ②
'mpilgrim'
① 음의 지표는 리스트의 끝에서부터 거꾸로 세어 원소에 접근합니다. 리스트의 마지막 요소는 언제나 li[-1]입니다.
② 음의 지표를 잘 모르겠다면 이런 식으로 생각해 보세요: li[-n] == li[len(li) - n]. 그래서 이 리스트에서는 li[-3] == li[5 - 3] == li[2]입니다.
예제 3.8. 리스트 조각썰기
- >>> li
- ['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[1:3] ①
['b', 'mpilgrim']
>>> li[1:-1] ②
['b', 'mpilgrim', 'z']
>>> li[0:3] ③
['a', 'b', 'mpilgrim']
① 지표를 두 개 지정하면 부분리스트를 얻을 수 있습니다. 이른바 “조각썰기(slice)”라고 부릅니다. 반환 값은 새로운 리스트로서 첫 조각 지표로부터 시작하여 (이 경우 li[1]), 두 번째 조각 지표 미만까지 (이 경우 li[3]) 리스트의 모든 원소를 순서대로 얻습니다.
② 조각썰기는 두 지표중 하나 또는 둘 모두 음수이더라도 작동합니다. 이런 식으로 생각하시면 좀 도움이 되겠습니다: 리스트를 왼쪽에서 오른쪽으로 읽어가면서 첫 조각 지표는 원하는 첫 요소를 지정하고 두번째 조각 지표는 원하지 않는 첫 요소를 지정한다고 생각하세요. 반환 값은 둘 사이에 있는 모든 것입니다.
③ 리스트는 지표가 0에서부터 시작합니다. 그래서 li[0:3]은 리스트에서 li[0]에서 시작하여 li[3] 미만까지 앞쪽 세 원소를 돌려줍니다.
예제 3.9. 간편 조각썰기
- >>> li
- ['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[:3] ①
['a', 'b', 'mpilgrim']
>>> li[3:] ② ③
['z', 'example']
>>> li[:] ④
['a', 'b', 'mpilgrim', 'z', 'example']
① 왼쪽 조각 지표가 0이면 생략해도 좋습니다. 묵시적으로 0으로 간주됩니다. 그래서 예제 3.8, “리스트 조각썰기”에서 li[:3]은 li[0:3] 과 같습니다.
② 비슷하게, 오른쪽 조각 지표가 리스트의 길이이면 생략해도 됩니다. 그래서 li[3:]은 li[3:5]와 같은데 이 리스트는 원소가 다섯 개이기 때문입니다.
③ 대칭성에 주목하세요. 이 다섯 개 원소 리스트에서 li[:3]은 첫 세 원소를 돌려주고 li[3:]은 뒤의 두 원소를 돌려줍니다. 사실, li[:n]은 언제나 첫 n 원소를 돌려주며 li[n:]는 그 나머지를 돌려줍니다. 리스트이 길이에 상관없이 말입니다.
④ 두 조각 지표 모두 생략되면 리스트의 모든 원소가 포함됩니다. 그러나 이는 원래 li 리스트와 같지 않습니다; 새로운 리스트로서 우연히 원소가 모두 같을 뿐입니다. li[:]는 리스트를 완벽하게 복사하는 지름길입니다.
3.2.2. 리스트에 원소 추가하기
예제 3.10. 리스트에 원소 추가하기
- >>> li
- ['a', 'b', 'mpilgrim', 'z', 'example']
>>> li.append("new") ①
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "new") ②
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(['two", "elements']) ③
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
① append는 원소 하나를 리스트의 끝에 추가합니다.
② insert는 원소 하나를 리스트에 끼워 넣습니다. 숫자 인자는 위치가 바뀌어 밀려나는 첫 원소의 지표입니다. 리스트 원소는 유일할 필요가 없다는 것을 주목하세요; 현재 똑 같은 값 'new'로 li[2]와 li[6]에 따로 원소가 있습니다.
③ extend는 리스트를 결합합니다. 여러 인자로 extend를 호출하고 있지 않다는 것을 주목하세요; 인자는 단 하나, 즉 리스트로 호출합니다. 이 경우 리스트는 원소가 두 개입니다.
예제 3.11. extend와 append 사이의 차이점
- >>> li = ['a', 'b', 'c']
- >>> li.extend(['d', 'e', 'f']) ①
>>> li
['a', 'b', 'c', 'd', 'e', 'f']
>>> len(li) ②
6
>>> li[-1]
'f'
>>> li = ['a', 'b', 'c']
>>> li.append(['d', 'e', 'f']) ③
>>> li
['a', 'b', 'c', ['d', 'e', 'f']]
>>> len(li) ④
4
>>> li[-1]
['d', 'e', 'f']
① 리스트는 extend 메쏘드와 append 메쏘드 두 개가 있는데 마치 같은 일을 하는 것처럼 보입니다. 그러나 사실은 완전히 다릅니다. extend는 언제나 리스트인 인자를 하나 취해서 그 리스트의 원소를 낱낱이 원래 리스트에 추가합니다.
② 여기에서 원소 세 개짜리 리스트 ('a'와 'b' 그리고 'c')로 시작했습니다. 그리고 리스트를 또다른 원소 세 개짜리 리스트 ('d'와 'e' 그리고 'f')로 확장합니다. 그래서 원소 여섯 개짜리 리스트입니다.
③ 반면에 append는 데이터 유형에 상관없이 인자를 하나 취해서 리스트의 끝에 단순히 덧붙입니다. 여기에서 인자 하나로 append 메쏘드를 호출하고 있습니다. 이 인자는 원소가 세 개인 리스트입니다.
④ 이제 원소 세 개로 시작한 원래 리스트는 원소가 네 개입니다. 왜 네 개인가? 방금 마지막에 덧붙인 마지막 원소는 그 자체로 리스트입니다. 리스트는 다른 리스트를 포함하여 어떤 유형이든 담길 수 있습니다. 그것이 바로 원하는 것일 수도 있고 아닐 수도 있습니다. extend를 뜻할 경우는 append를 사용하지 마세요 .
3.2.3. 리스트 검색하기
예제 3.12. 리스트 검색하기
- >>> li
- ['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example") ①
5
>>> li.index("new") ②
2
>>> li.index("c") ③
Traceback (innermost last):
File "", line 1, in ?
ValueError: list.index(x): x not in list
>>> "c" in li ④
False
① index 메쏘드는 리스트에서 첫 번째 나타나는 값을 찾아 그 지표를 돌려줍니다.
② index 메쏘드는 리스트에서 처음 나타나는 값을 찾습니다. 이 경우, 'new'는 리스트에서 li[2]와 li[6]에서 두 번 나타납니다. 그러나 index는 오직 첫 지표만 돌려줍니다. 즉 2를 돌려줍니다.
③ 리스트에서 값이 발견되지 않으면 파이썬은 예외를 일으킵니다. 이는 대부분의 언어와 현저하게 다른데 다른 언어에서는 유효하지 않은 지표를 돌려줍니다. 이는 약간 성가셔 보일 수도 있습니다. 그러나 나중에 유효하지 않은 지표를 사용하려고 시도하는 것 보다 문제가 있는 소스에서 프로그램이 충돌을 일으킨다는 뜻이기 때문에 좋은 일입니다.
④ 리스트에 값이 있는지 테스트하려면 in을 사용하세요. 값이 발견되면 True를 돌려주고 그렇지 않으면 False를 돌려줍니다.
☞ 2.2.1 이전 버전에서는 파이썬에 따로 불리언 데이터유형이 없었습니다. 이를 채우기 위해 파이썬은 (if 서술문 같은) 불리언 문맥에서 다음과 같은 규칙에 따라 거의 어떤 것이든 받아들였습니다:
- 0은 거짓이다; 다른 숫자는 모두 참이다.
- 빈 문자열("")은 거짓이다; 다른 모든 문자열은 참이다.
- 빈 리스트([])는 거짓이다; 다른 모든 리스트는 참이다.
- 빈 터플(())은 거짓이다; 다른 모든 터플은 참이다.
- 빈 사전({})은 거짓이다; 다른 모든 사전은 참이다.
이 규칙은 여전히 파이썬 2.2.1 이후에도 적용되지만 이제는 실제로 True나 False를 가지는 불리언 값을 사용할 수도 있습니다. 대문자에 주의하세요; 이 값들은 파이썬의 다른 것들과 마찬가지로 대소문자에 민감합니다.
3.2.4. 리스트에서 원소 제거
예제 3.13. 리스트로부터 원소 제거하기
- >>> li
- ['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.remove("z") ①
>>> li
['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("new") ②
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("c") ③
Traceback (innermost last):
File "", line 1, in ?
ValueError: list.remove(x): x not in list
>>> li.pop() ④
'elements'
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
① remove는 리스트에서 제일 처음 출현하는 값을 제거합니다.
② remove는 제일 처음 나타나는 값만 삭제합니다. 이 경우, 'new'는 리스트에서 두 번 나타났지만 li.remove("new")는 첫 번째 나타난 것만 삭제합니다.
③ 리스트에서 값이 발견되지 않으면 파이썬은 예외를 일으킵니다. 이 행위는 index 메쏘드를 흉내낸 것입니다.
④ pop은 흥미로운 메쏘드입니다. 두 가지 일을 하는데: 리스트에서 가장 마지막 원소를 꺼내서 그 값을 돌려줍니다. 주의하세요. 값을 돌려주지만 리스트는 바뀌지 않는li[-1]와 다르며, 리스트를 바꾸지만 값은 돌려주지 않는 li.remove(value)와 다릅니다.
3.2.5. 리스트 연산자 사용하기
예제 3.14. 리스트 연산자
- >>> li = ['a', 'b', 'mpilgrim']
- >>> li = li + ['example', 'new'] ①
- >>> li
['a', 'b', 'mpilgrim', 'example', 'new']
>>> li += ['two'] ②
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
>>> li = [1, 2] * 3 ③
>>> li
[1, 2, 1, 2, 1, 2]
① 리스트는 + 연산자로 결합할 수 있습니다. list = list + otherlist는 결과가 list.extend(otherlist)와 같습니다. 그러나 + 연산자는 새로 (결합된) 리스트를 값으로 돌려주는 반면, extend는 기존의 리스트를 바꾸기만 할 뿐입니다. 이는 extend가 더 빠르며, 특히 커다란 리스트에 적합하다는 뜻입니다.
② 파이썬은 += 연산자를 지원합니다. li += ['two']는 li.extend(['two'])와 동등합니다. += 연산자는 문자열과 정수 그리고 리스트에 작동합니다. 그리고 사용자-정의 클래스에 맞게 작동하도록 오버로드도 가능합니다. (클래스에 관해서는 제 5 장에서 더 자세하게 다룹니다.)
③ * 연산자는 리스트에 반복자로 작동합니다. li = [1, 2] * 3는 li = [1, 2] + [1, 2] + [1, 2]와 동등한데, 세 리스트를 하나의 리스트로 결합한 것입니다.