ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 4. (1) 파이썬 자료형 리스트
    파이썬(Python) 강의 2019. 2. 5. 17:14

    지난번 두 포스트에서는 파이썬 자료형 중 하나인 문자열에 대해서 알아보도록 했다. 이번 포스트에서는 마찬가지로 파이썬 자료형인 리스트를 알아보도록 하겠다. 내용이 많아 포스트를 두개로 나눠 앞 부분은 자료형 자체에 대해서 설명하고, 뒷 부분은 리스트가 가지고 있는 기능(오퍼레이션)위주로 설명하도록 하겠다.

    들어가기전에

    이 포스트는 여러분이 파이썬을 설치했고 각자 원하는 IDE를 이용해 파이썬을 개발한다고 가정한다. 대화형(Interactive) 터미널을 사용해도 상관 없다. 혹시 파이썬을 설치하지 않았다면  1.파이썬 설치 및 개발환경 설정 이 포스트에서 파이썬과 파이썬 개발환경을 먼저 셋업하길 바란다. 앞서 말했듯이 반드시 실습 해 보길 바라고 30분 이상 소요하지 말라. 또한 이전 포스트인 3. (1) 파이썬 자료형 문자열에서 스트링(문자열)에 대해 먼저 학습 한 후 이 포스트를 진행해라.

    • 숫자(Numbers) : 12, 24.3, 3+2j, .. (2.파이썬 자료형 숫자)

    • 문자(Strings) : "hello, "world" (이전 포스트: 3. (1) 파이썬 자료형 문자열, 3.(2) 파이썬 자료형 문자열)

    • 리스트(Lists) : [1, 3, [3, 'hey'], 4] <- 이 포스트에서 다루는 자료형 

    • 딕셔너리(Dictionaries) : { 'name': 'fsoftwareengineer', 'age' : 17}

    • 튜플(Tuples) : (1, 'a', 4, 'c')

    • 파일(Files) : f = open('filename', 'r')

    • 셋(Sets) (집합) : { 1, 4, 5 }

    • 다른 타입들 : Boolean (True/Faluse), types, None, etc

    • 프로그래밍 유닛 타입(Programming unit types) : 함수(Functions), 모듈(Modules), 클래스(Classes)

    • 구현 레벨 타입(Implementational-level types) : 예외(Exception) 등등..

    목표

    • 리스트 (List)
    • 리스트의 시퀀스 오퍼레이션 - 인덱싱 및 슬라이싱 (Indexing and Slicing)
    • 가변성 (Mutability)
    • 중첩리스트 (Nested List)
    • 행렬 (Matrix)

    예상 소요 시간 30분 내외

    리스트 (List)

    인간 세계에서 리스트란 무엇인가?

    • Apple
    • Strawberry
    • Banna
    • Orange

    이렇게 점을 콕콕찍어서 나열 한 것을 리스트라고 부른다. 보통 우리가 리스트를 적을 때는 위에서 아래로 불렛포인트를 찍어서 나열한다. 파이썬에서도 마찬가지이다. 파이썬에서는 리스트를 대괄호 안에, 콤마로 나누어서 나열한다. 

    ["apple", "strawberry", "banana", "orange"]

    위의 리스트는 문자열로 이루어진 리스트이다. 그렇다면 리스트 안의 자료형은 모두 같아야 할까? 아니다. 리스트에서는 다른 자료형을 섞어서 쓸 수 있다.

    ["apple", 33, "banana", "orange"]

    중간에 정수형이 들어가도 상관없다. 이렇듯 리스트는 순서가 있는 오브젝트들의 집합이다.

    오브젝트란 무엇인가?

    여러분이 사용하는 모든 자료형이 오브젝트이다. 문자열, 숫자, 리스트, 이후에 배우게될 수 많은 다른 자료형 및 여러분이 직접 만들게 될 클래스도 전부 Object이다. 

    그럼 안의 오브젝트들은 실제로 어떻게 저장되어있는가? 지난번에 배운 문자열을 아래처럼 표현 했던 것을 기억하는가? "apple"을 예를 들어 보자.

    지난번읜 "sequence"처럼 "apple"도 어떤 공간에 문자가 하나 하나씩 들어 있을 것이다. 그렇다면 리스트에서는 어떻게 이를 어떻게 표현할 수 있을까? 이런 느낌일까? 문자열에서 했던 것 처럼, 같은 하나하나 차곡차곡 내부에 쌓일까?


    답은 그렇지 않다이다. 이렇게 리스트안에 a부터 e까지 첫번째 칸에 쌓여있고, 그 다음에는 33이 나오고 할 것 같지만 실제로 리스트는 그렇게 생기지 않았다. 완전히 똑같진 않지만, 대략 아래와 같은 느낌이라고 생각하면 좋을 것 같다.

    이게 대체 무슨 말이냐.... 문자열 첫 부분에서 자료형에 대해 설명 할 때, 자료형은 메모리 공간과, 표현 방식, 그리고 기능(오퍼레이션)들로 구성된다고 했던 것을 기억하는가? 리스트 같은 경우, 안에 들어갈 내용들을 차곡차곡 쌓는 대신, 안에 들어갈 내용(아이템)들을 메모리 어딘가에 놔두고, 리스트 자체는 그 내용의 "주소"를 기억한다. 이 주소를 파이썬에서는 "레퍼런스(Reference)"라고 부른다. 예를들어 당신이 삐멜의 웹사이트를 갖고 싶다면 여러분의 컴퓨터에 모든 삐멜 포스트를 복사/붙여넣기해서 가지고 있는 편이 더 관리하기 쉽겠는가, 아니면 삐멜의 웹사이트 주소인 https://imasoftwareengineer.tistory.com을 어딘가에 저장 또는 북마크 해 놓는 게 더 관리하기 쉽겠는가? 마찬가지이다. 삐멜 웹사이트만 관리한다면 포스트를 전부 복붙 할 수도 있겠지만, 다른 웹사이들도 모두 복사/붙여넣기 할 것인가? 아니다, 우리는 링크를 어딘가에 저장하던지, 북마크를 하던지 해서 여러분이 관심있는 사이트의 "주소"를 기억하고 사이트의 내용이 필요 할 때마다 브라우저를 이용해 그 주소를 따라간다. 그러면 여러분이 찾던 사이트의 내용이 나온다. 마찬가지이다. 리스트도 "주소(레퍼런스)"를 가지고 있고, 필요 할 때마다 (여러분이 list[0]나 list[3]을 부를 때 마다) 그 주소(레퍼런스)를 따라가서 내용물을 가져온다. 따라서 저 노란 동그라미가 각 아이템의 레퍼런스라고 생각하면 좋겠다. 혹시 이해하기 어렵다면 한번 읽고 넘어가라, 뒤로 가면 레퍼런스에 대해 또 설명 할 기회가 있을 것이다. 이후 나올 설명에서는 설명을 간편하게 하기 위해 리스트 내부에 아이템들이 있는 것 처럼 표현 했지만 실제로는 그렇지 않다는 사실을 염두 해 두자.

    그럼 다음은 리스트의 접근 방법과 시퀀스 오퍼레이션에 대해 알아보자.

    리스트의 시퀀스 오퍼레이션 - 인덱싱 및 슬라이싱

    인덱싱 (Indexing)

    여러분은 지난 두 포스트에서 다뤘던 문자열의 시퀀스 오퍼레이션에 대해서 기억하는가? 시퀀스는 말 그대로 왼쪽에서 오른쪽으로 나열 된 것을 의미하며 내부의 아이템을 인덱스를 이용해 접근 할 수 있다고 했다. 리스트도 마찬가지이다. 다음을 실습 해 보자.

    list = ["apple", 33, "banana", "orange"]
    print(list[2]) banana

    바나나가 출력되는 것을 확인 할 수 있다.


    문자열을 학습 했을 때를 생각 해 보자, 저 파랑과 초록의 중간쯤인 색의 네모칸에 s,q,u,e,n,c,e라는 문자들이 하나하나 들어있었다. 이제는 무엇이 들어있는가? 이제는 문자열 그 자체, 또는 숫자 그 자체가 한 칸에 들어있다. 그리고 list[2]를 부를 시 인덱스가 2인 곳에 들어있는 녀석을 접근하게 되는 것이다. 또 문자열과 마찬가지로 음수 인덱싱이 가능하다.

    list = ["apple", 33, "banana", "orange"]
    print(list[-3]) 33

    위 처럼 len(list)-1을 시작으로 -1, -2, -3, -4... 순으로 음수 인덱싱이 가능하다.

    슬라이싱 (Slicing)

    문자열에서 s = "sequence"를 s[1:3]을 이용해 인덱스가 1보다는 크거나 같고 3보다는 작은 문자열을 리턴 했던 것을 기억하는가? (안나면 돌아가서 확인 해 보길 바란다.) 리스트도 시퀀스의 일종이므로 [:]오퍼레이션이 가능하다. [:]오퍼레이션을 파이썬에서는 슬라이싱이라고 부른다. 실습을 위해 좀 더 많은 아이템을 넣고 슬라이싱을 해 보자.

    list = ["apple", 33, "banana", "orange", "melon", 41, 0, "cherry"]
    print(list[1:4]) [33, 'banana', 'orange']

    앞의 포스트에서 말했듯 [최소포함인덱스:최대인덱스]로 리스트를 말그대로 잘라낸다(slicing).

    가변성(Mutability)

    Mutability를 대체할 한국말이 없어서 꽤나 고생했다. Mutability란 리스트 내부의 오브젝트들을 임의로 변경 할 수 있음을 의미한다. 문자열의 불변성(Immutability) 내용이 생각나는가? 간단히 말에 어떤 문자열을 선언하면 그 문자열 내부의 문자들을 인덱싱을 이용해 임의로 변경 할 수 없다는 뜻이었다. 예를들어 s = "sequence"라는 구문이 있을 때 s[3] = 'a'를 이용해 인덱스가 3인 곳의 문자를 바꾸려 하면 에러가 났었다. 하지만 리스트는 인덱스의 내부를 변경 할 수 있다. 다음의 예제를 보자.

    list = ["apple", 33, "banana", "orange", "melon", 41, 0, "cherry"]
    list[2] = "MANGO" # list의 2번째 인덱스 자리에 "MANGO"를 집어 넣어라.
    print(list)

    ['apple', 33, 'MANGO', 'orange', 'melon', 41, 0, 'cherry']

    "banana"가 "MANGO"로 바뀌었다! 이렇게 어떤 오브젝트(여기에서는 리스트)의 내부를 바꿀 수 있을 때, 그 오브젝트는 Mutable하다고 부르고 Mutability가 있다고 한다.

    중첩리스트 (Nested List)

    위의 설명에서, 리스트는 순서가 있는 오브젝트들의 집합이다. 그리고 오브젝트는 모든 자료형을 의미한다고 했다. 그렇다면 리스트는 리스트를 포함 할 수 있는 것인가?? 리스트 자체도 오브젝트이니까 말이다. 그렇다! 리스트는 리스트 자체를 포함 할 수 있고 우리는 이것을 중첩 리스트 (Nested List)라고 부른다. 다음을 실행 해 보자.

    list = ["apple", 33, "banana", "orange", "melon", 41, 0, "cherry", ["my", "second", "list"]]
    print(list) ['apple', 33, 'banana', 'orange', 'melon', 41, 0, 'cherry', ['my', 'second', 'list']]


    자 그럼 맨 뒤에 있는 중첩된 리스트는 어떻게 가져올까? 다른 오브젝트들을 가져올 때와 마찬가지로 인덱스를 이용해 접근하면 된다.

    list = ["apple", 33, "banana", "orange", "melon", 41, 0, "cherry", ["my", "second", "list"]]
    print(list[8]) ['my', 'second', 'list']

    그렇자면 리스트 통째로가 아닌 'second'만 가져오고 싶다면 어떻게 해야 하나? 지금 list[8] = ['my', 'second', 'list']가 담겨있다. 예를들어서 mySecondList = ['my', 'second', 'list']가 있을 때 'second'를 어떻게 가져오겠는가? mySecondList[1]로 가져오면 될 것이다. mySecondList에 담긴 리스트는 list[8]에 담긴 리스트와 완전 동일하다. 즉, mySecondList == list[8]인 셈이다. 그렇다면 list[8]의 두번째 오브젝트는 어떻게 가져오는가? 그렇다. list[8][1]을 통해 가져오면 된다. list[8]대신 mySecondList를 대입하면 이해하기 쉬울 것이다. 잘 모르겠다면 다음을 실행 해 보자.

    list = ["apple", 33, "banana", "orange", "melon", 41, 0, "cherry", ["my", "second", "list"]]
    mySecondList = list[8]
    print(list[8][1], mySecondList[1]) second second

    list[8][1]도 mySecondList[1]도 'second'를 리턴하는 것을 볼 수 있다.

    행렬 (Matrix)

    중첩 리스트가 가능하다는 리스트의 특성을 이용하면 리스트를 이용해 행렬을 구현 할 수 있다. 다음의 3x3 행렬을 보자.

    matrix = [
    [1, 2, 3],
    [10, 20, 30],
    [100, 200, 300]
    ]

    print(matrix[0][0]) 1

    첫번째 인텍스를 통해 행(row)을, 두번째 인덱스를 통해 열(column)을 명시 할 수 있다.

    이번 포스트에서는 리스트, 리스트를 사용 하는 법, 리스트의 시퀀스 오퍼레이션과 Mutability 그리고 중첩 리스트 및 리스트를 이용한 행렬 표현에 대해 알아보았다. 다음 포스트에서는 리스트에서 제공하는 기본 함수들에 대해서 설명하고 실습 해 보도록 하겠다. 

    혼자 해보기

     Q 1) 아래의 리스트에서 apple의 e만 가져오려면 어떻게 해야하는가?

    list = ["apple", 33, "banana", "orange"]

    Q 2) 다음을 실행 해 보고 "레퍼런스"에 대해 잘 생각 해 봐라.

    fruitList = ["apple", "banana", "orange", "mango"]
    list = [fruitList, fruitList]
    print(list)
    fruitList[1] = "MELON"
    print(list)


    댓글

f.software engineer @ All Right Reserved