[Python101] Iterable (1) – 리스트

지난 시간 for 문을 설명할 때 다음과 같은 문법이 잠깐 등장했다.

for number in range(1,10):

이 구문은 range() 함수를 사용해 만들어지는 1~9 까지의 숫자의 ‘집합’의 개별 원소에 대해 반복적인 명령을 수행하는 구문이라고 했다. 이러한 집합은 사실 영어로 ‘iterable’이라고 하지만 우리말로는 딱히 정확히 대응시킬만한 말이 없다는 것도 이야기했다. 이번 시간에는 이 iterable에 대해서 알아보고자 한다.

* 이번 시간은 IDLE의 대화형 쉘을 통해 직접 확인해보면서 배우는 것이 좋다.

지난 시간에서 사용한 ‘집합’이라는 표현이 어찌보면 가장 근접한 표현일 수도 있다. iterable이라는 말은 ‘집합’ 그 자체보다는 “개별 원소를 반복적으로 셀 수 있는”이라는 문맥적인 의미가 있기 때문이다. 파이썬에서 사용하는 집합에는 1) 리스트, 2) 튜플, 3) 사전(dictionary) 가 있다. 각각은 약간의 차이점은 있으나, 대체로 for 문과 같은 반복 작업에서 원소들을 일일이 열거 한다는 점에서 공통점을 가진다.

리스트

프로그래밍 언어를 배울 때 빠지지 않고 등장하는 개념이 있으니, 바로 ‘배열(array)’이다. 배열은 수학에서의 ‘집합’과 매우 유사하기도 한데, 파이썬의 리스트는 바로 이 배열과 거의 같은 개념이라 볼 수 있다.

리스트는 여러 개의 원소를 포함하는 하나의 집합체이다. 리스트에 포함되는 개별 값들을 원소라 할 수 있는데, 이 원소들은 모두 일정한 순서를 가지고 있다. 특정한 원소의 순서를 ‘인덱스’라고 한다.

리스트는 대괄호로 여러 값들을 연속해서 둘러 싸 만들 수 있다. 이 때 각 값들은 컴마(,)로 구분된다.

a  = [2,3,5,7,11,13,17,19]

a 라는 변수에 20보다 작은 소수(prime number)로 구성된 리스트를 만들어 대입했다. 이 때 작은 수 부터 큰 수의 순서로 쓴 것은 단지 편의의 문제일 뿐이다.

b = [5,19,2,7,13,11,3,19]

와 같이 불규칙한 순서를 써서 만든 리스트 b는 구성하고 있는 원소는 a와 같지만 각각의 원소의 순서가 다르다. (따라서 둘은 완전히 다른 리스트이다.)

하나의 원소의 인덱스

리스트의 각 원소는 정해진 순서가 있다고 했다. 이 때의 순서값을 ‘인덱스’라고 하며, 인덱스는 0부터 시작한다. 즉 첫번째 원소의 인덱스는 항상 0 이다.

리스트로부터 특정한 인덱스에 위치한 원소를 지정하려면 리스트이름[인덱스]와 같은 식으로 접근하게 된다.

print a[2]
#==> 5

마찬가지로 c = a[5] 와 같은 식으로 특정 원소를 다른 변수에 대입하는 것도 가능하다.

파이썬의 리스트는 재미있게도, 독특한 인덱스를 취급한다. 바로 음수 인덱스이다.

print a[2]
print a[-2]

위 명령은 리스트 a의 뒤에서 두 번째 원소를 가리킨다. 즉 17을 출력하게 된다.

리스트의 부분집합

리스트는 수학적 개념의 ‘집합’과도 매우 유사하다고 했다. 그리고 인덱스를 사용해서 특정한 원소에 접근하는 것이 가능하다고도 했다. 이와 마찬가지로 인덱스를 사용하여 부분 집합을 정의할 수 있다.

c = a[2:5]
print c

위의 코드는 리스트 a로부터 부분집합인 c를 추출하는 과정을 보여준다. a[2:5]는 2번째 인덱스에서 5번 인덱스까지를 말하는데, 주의할 것은 뒤쪽 인덱스는 포함하지 않는다. 즉 2번, 3번, 4번의 인덱스에 해당하는 원소만이 추출되는 것을 확인할 수 있다.

만약 :을 쓰고 한쪽을 비운다면 끝까지에 해당한다.

d = a[3:] # -> [7, 11, 13,19]
#인덱스           3   4   5  6
e = a[:5] # -> [2, 3, 5, 7, 11]
#인덱스           0  1  2  3   4

이 때도 뒤쪽 인덱스는 포함하지 않는 다는 점에 주의하자. 이는 range() 함수에서도 동일하게 적용되었다. range(2,10) 은 2에서부터 숫자 범위를 리스트로 만들어서 반환해 준다. 이 때 뒤쪽에 들어가는 10은 포함되지 않아서 9까지만 들어가게 된다. 여기서 중요한 것! 바로 range()  함수가 결과값을 list로 반환해준다는 것이다.

(시작값, 끝값) ==> range() ==> [시작값 ~ 끝 값]으로 된 리스트

문자열과 리스트

list는 리스트를 지칭하는 파이썬의 예약된 단어이다. “리스트라는 데이터 타입”을 의미한다. 같은 이름의 함수인 list()는 특정한 객체를 리스트로 만들어준다. 문자열은 한글자, 한글자의 문자가 이어져서 단어나 문장이 된 텍스트 정보를 의미하는데, 이는 한글자씩으로 만들어진 리스트와 비슷하지 않은가?

str = 'elephant'
g = list(str)
print g
# ['e','l','e','p','h','a','n','t']

문자열과 리스트를 오가는 표현은 이후로도 자주 등장할 것인데, 아마도 별도의 챕터로 분리해서 설명하는 것이 좋겠다는 생각이 든다.

list 는 파이썬에서 “리스트라는 데이터 타입”을 의미한다고 했다. 따라서  dir(list)라고 해보면 리스트가 가지고 있는 기능들을 열람할 수 있을 것이다.

dir() 명령을 통해 확인할 수 있는 리스트의 동작은 다음과 같다. (각각의 명령에 대해서 도움말은 help(list.pop) 과 같은 식으로 찾아볼 수 있다.

  • append(x) : 리스트의 끝에 새로운 원소 x를 추가한다.
  • count(x) :  리스트에서 x 라는 원소가 몇 번 들어있는 지 세어본다.
  • extend(x) : 리스트에 새로운 리스트 x를 연결해준다.
  • index(x) : 리스트에서 x라는 원소의 인덱스를 구해준다. 이 때 x가 두 개 이상 들어있다면, 맨 처음 x만 찾는다.
  • insert(인덱스, x) : 현재 리스트의 주어진 인덱스 위치에 x라는 원소를 끼워넣어준다.
  • pop() : 리스트의 맨 마지막 원소를 반환하고, 해당 원소를 원래 리스트에서 제거한다. 만약 pop(x) 라고 하면 x를 반환하고, 리스트는 x를 제거한다.
  • remove(x) : 리스트에 포함된 원소 x를 제거한다. (pop과는 달리 뭔가 반환하지는 않는다.)
  • reverse() : 리스트를 역순으로 바꾼다.
  • sort() : 리스트의 원소들을 정렬한다.

리스트를 다루는 함수

리스트 자체가 제공하는 함수는 ‘메소드’라고 부른다. reverse, pop, sort 등은 리스트의 메소드이다. 앞서 정의한 a의 경우에는 다음과 같이 실행해 볼 수 있다.

a.reverse()
print a # --> [19, 17, 13, 11, 7, 5, 3, 2]
a.pop()
#--> 2
print a #--> [19, 17, 14, 11, 7, 5, 3]
a.sort()
print a #--> [3, 5, 7, 11, 13, 17, 19]

이러한 리스트 자체의 메소드 외에도 몇 가지 리스트와 관련된 기본 함수들이 있다. 이 중에서 가장 자주 쓰이는 것은 len()sorted() 함수이다. len 함수는 리스트의 원소의 총 개수를 (즉 리스트의 길이를) 반환하고, sorted() 함수는 인자로 받은 리스트를 정렬한 사본을 반환한다. sorted() 함수는 원본 리스트의 원소의 순서를 바꾸지 않는다. 반면, 리스트의 list.sort() 메소드는 원본 리스트의 순서를 바꾼다.

그리고 list()라는 함수는 위에서도 잠깐 살펴보았지만, 리스트로 변경이 가능한 데이터형을 쪼개거나 변환하여 리스트로 만들어 반환한다. 문자열을 리스트로 바꾸거나 다른 “집합” 형식인 튜플을 리스트로 바꿀 수 있다.

리스트의 효용

다른 프로그래밍 언어에서도 배열은 매우 중요한 데이터 형식으로 취급한다. 일련의 데이터를 한 덩어리로 다루거나, 목록으로 관리하거나 하는 등 실질적인 어플을 만들 때 상당히 많이 적용된다.

또한 “스택”이나 “큐”와 같은 개념 역시 배열을 이용해서 구현한다. (스택이나 큐는 다른 글을 통해서 알아보도록 하자. 혹은 구글에서 검색을 해봐도 좋다.)

또한 문자열과 리스트를 서로 변환해가면서 처리하는 것 역시 매우 유용하게 활용된다.

다음 시간에는 리스트를 문자열과 어떻게 함께 사용하여 활용하는지, 그리고 조금 더 멋진 “지능형 리스트”란 무엇인지를 잠깐 살펴보겠다.