튜플의 특징

튜플은 리스트만큼 많이 사용되는 자료구조이다.

어떤 데이터를 묶음으로 반환하는 많은 함수나 메소드들은 리턴값을 튜플로 반환한다.

그렇기 때문에 튜플에 대한 이해는 리스트 못지 않게 중요하다.

같이 보면 좋은 저장소는 CPython : Tuple Object이다.

참고로 이번 글은 사진보다 글 위주로 될 것이다.

튜플도 객체들의 모음

앞서 리스트는 객체 참조자들을 저장하는 컨테이너라고 했다.

튜플은 요소를 순서대로 결합한 요소들의 쌍이다. 리스트와 마찬가지로 여러 자료형들을 함께 저장할 수 있다.

이런 점에서 왜 굳이 리스트와 구분되는 자료형이 있는걸까?
면접에서도 자주 나오는 질문인데, 파이썬에서 리스트와 튜플의 차이점은 무엇일까?

두 자료구조의 가장 큰 차이점은 값을 수정할 수 있는 가변객체냐, 불변객체냐이다.

근데 왜 굳이 이게 중요하냐라는 생각이 들 수 있는데, 데이터를 변화시키면 안되는 경우가 존재할 수 있기 때문이다. 파이썬에서 함수의 리턴값을 여러 개로 하면 팩킹의 형태로 변수가 전달된다.

이는 함수가 리턴하면서 혹시 모르게 값이 변화되는 것을 막아줄 수 있다.

그 외에는 리스트와 큰 차이는 없다. 객체의 참조들을 저장하는 특징도 동일하다.

여기서 가변객체냐 불변객체냐는 파이썬의 메모리관리 측면에서 중요한 역할을 한다.

이는 결과적으로 속도와도 연관이 되는데, 다시 맨 처음 포스트로 돌아가보면 -5 ~ 256은 미리 만들어진 객체를 사용한다고 했다. 그래서 해당 범위의 수를 사용하는 경우에는 약간이나마 조금 더 시간이 빠르다.

튜플의 특징을 정리하면 다음과 같다.

  • 리스트보다 적은 메모리를 차지하고 성능면에서 더 빠르다.
    • 리스트보다 적은 메모리를 차지하는 이유는 이전에 말했듯이 리스트는 확장에 대비하고자 좀 더 여유있게 메모리를 확보한다. 하지만 튜플은 내부 구조를 변화하지 않으므로 굳이 메모리를 여유있게 확보할 필요가 없다.
  • 내부 값을 실수로 변경하는 것에 대비할 수 있다.
  • 딕셔너리 키로 사용가능하다.

튜플과 변수

튜플과 리스트를 생성하는 방식에는 각자의 이름을 가진 함수를 호출하는 방식이 있다. 이 둘은 생김새는 동일하지만 동작과정에서 큰 차이가 있다. 이는 결국 가변 객체냐 불변 객체냐로 다시 연결된다.

lst1 = [1, 2, 3, 4]
lst2 = list(lst1)

tp1 = (1, 2, 3, 4)
tp2 = tuple(tp1)

lst1lst2는 서로 다른 객체가 생성되어 각각의 변수가 참조한다고 했다. 그렇다면 튜플은 어떻게 될까? 아주 잠깐 생각해보면 쉽게 답을 유추할 수 있다. 힌트는 불변 객체이다.

두 튜플의 아이덴티티는 동일하게 나온다. 왜일까? 이는 튜플의 생성 방식때문에 나타난다.

튜플은 동일한 튜플 객체에 대해 같은 참조를 하게된다. 이는 튜플이 불변 객체라 어차피 변경을 할 수 없는 데이터라서다. 그래서 같은 실체를 함께 참조하더라도 큰 문제가 발생하지 않기 때문에 동일한 참조를 가리킨다.

튜플의 누적 대입

튜플은 불변 객체라서 누적 대입(+=)이 불가능할 것 같지만 사용할 수 있다. 하지만 리스트의 누적 대입의 메모리 활용과 다르게 동작한다. 이유는 역시나 불변 객체라서이다.

tp1 = (1, 2, 3, 4)
tp1 += (5, )

누적 대입을 하게되면 새로운 튜플이 만들어지고 객체 참조가 바뀌게 된다. 이 점을 잘 알아둘 필요가 있다.

간단하게 정리하면 튜플은 동일한 객체는 새로 생성하지 않고 참조를 할당하고 조금이라도 변화를 주면 새로운 객체를 만들어서 참조한다.


딕셔너리의 특징

딕셔너리도 튜플과 리스트 못지 않게 많이 사용되는 자료구조이다. Key-Value의 쌍으로 이루어진 자료구조이고 자료구조 수업시간에 배우는 딕셔너리 구조를 생각하면된다. 여기서 조금 센스있는 사람 또는 열심히 자료구조 공부를 한 사람이라면 스쳐지나가는 생각이 있다. 딕셔너리는 해시테이블 구조를 가질까?
정답은 맞다이다. 딕셔너리는 해시 테이블을 통해 구현되었기 때문에 키 탐색이 빠르다는 장점이 있다.

딕셔너리의 키

딕셔너리는 Key-Value가 한 쌍으로 이루어진 자료구조이다. 대부분의 언어에서 Key-Value 쌍의 자료구조에서 Key가 중복되지 않는 고유한 값이어야한다. 이는 파이썬도 마찬가지이다.
우선 딕셔너리는 가변 객체에 속한다. 하지만 딕셔너리의 key는 불변이다. 일반적으로 키에 문자열을 많이 쓰지만 불변 객체라면 모두 사용할 수 있다. 이 말은 튜플도 키로 쓸 수 있다.

딕셔너리에서 값을 가져올때는 get을 써라

이 글을 읽는 대부분의 사람들이 기본적인 딕셔너리 생성이나 사용법은 알 것이라 생각한다. 딕셔너리에서 value를 가져오는 방법은 크게 2가지가 존재한다.

  • dict[key]
  • dict.get(key)

둘 중 어떤걸 쓰든 값이 '있다면', 가져오는 데엔 큰 특징은 없다. 하지만 dict.get(key)로 값을 가져오는 것을 추천한다. 이유는 인덱스식으로 값을 가져올 경우 해당하는 key가 없다면 KeyError 예외를 발생시킨다. 하지만 dict.get(key)은 자신이 원한 값은 default로 설정해서 key가 없는 경우 default값을 반환한다. default를 따로 설정하지 않으면 None이 기본으로 설정되어 있다.

딕셔너리 활용

딕셔너리에서 update를 사용하면 딕셔러니를 합치거나 새로운 쌍을 추가할 수 있다. 활용은 아래처럼 사용한다.

rgb = {"red": "빨강", "blue": "파랑", "green": "초록"}
fruit = {"yellow": "바나나", "red": "사과", "purple": "포도"}

rgb.update(fruit)

근데 만약 위의 예제처럼 같은 키인데 다른 value를 가지면 어떻게 될까?
update라는 이름에 걸맞게 새롭게 들어오는 key-value 기준에 맞춰 데이터가 바뀌게 된다.

update를 활용하면 특정 키의 요소를 변경하는 것도 가능하다. 이때, dict.update(key=value)를 적으면 되는데 오타가 아니라 key는 문자열로 적지 않고 key 이름 자체를 적는다.


set의 특징

set은 이름 그대로 집합이다. 중학교에 들어가서 수학책을 피면 가장 맨 처음 만나는 친구가 집합이다. 아마 공부를 아무리 안 한 사람이라도 집합은 공부했을 것이다. 왜냐? 첫 챕터니까...
집합의 가장 큰 특징은 순서와 중복이 없는 값들의 모임이다. 이런 수학적 성질은 파이썬의 set에서도 동일하게 적용된다.

set의 선언

set을 선언하는 방식은 여러가지가 있다.

st1 = {1}
st2 = set()
st3 = set([1, 2, 3])

여기서 주의해야할 것은 빈 set을 만들때는 반드시 set()을 사용해야한다. 이유는 set을 나타내는 연산자는 {}인데, 만약 빈 {}을 사용할 경우 빈 딕셔너리가 만들어진다.

set에 대한 이해

set은 가변 객체이다. 물론 불변 객체로 사용하는 방법도 있다. 이는 fronzeset 타입이 있고 필요에 따라 라이브러리를 활용해 쓸 수 있다. 물론 불변 객체니까 frozenset은 딕셔너리 키로 쓸 수 있다.

set도 값을 추가하거나 삭제할 수 있다. 추가를 할 때는 set.add(e)를 사용하면 값이 추가된다. 물론 이미 있으면 추가되지 않는다.
제거하는 과정에는 2개의 메소드가 있다. 하나는 discard, 다른 하나는 remove이다. 둘 중 어느 것이 좋냐?라는 질문을 한다면, 에러를 발생시키지 않는 쪽이 서비스하기에 유리할 것이다. 그렇다면 discard를 써야한다. remove는 값이 없다면 KeyError 예외를 발생시킨다.


파이썬을 깊게 다뤄보는 3번째 시간이었다. 자료형을 그냥 쓰면 되는거지...라는 생각이 들 수도 있는데, 파이썬을 익숙하게 다룬다고 말하거나 다뤄야 한다면 변수가 어떻게 동작하는지, 메모리 구조를 어떻게 처리하는지는 알아야하지 않을까 싶다.

반응형