[파이썬] 배열 형태의 자료구조

I. 튜플(tuple)과 네임드 튜플(named tuple)

가. 튜플(tuple)

  • 튜플은 변경 불가 클래스로, 객체 생성 후 원소를 변경, 삭제, 추가할 수 없고 색인 연산을 통해 조회만 가능
  • [예제] 튜플 (tuple)
t = tuple((1, 2, 3, 2, 1)) # 튜플 객체를 리터럴로 표기(쉼표로 구분)
print(t.count(2))   # 원소 값(2)의 개수를 count
print(t.index(3))   # 인덱스 정보의 원소 조회

[결과]
2
2

나. 네임드 튜플(named tuple)

  • 각 원소에 이름을 붙이고 이름으로 원소에 접근
  • [예제] collections 모듈을 사용한 네임드 튜플 (named tuple)
import collections as cols # 여러 원소를 가진 collections 모듈 import

NamedTupleClass = cols.namedtuple("NamedTuple", "x, y, z") # 새로운 네임드 튜플 클래스 생성

nt = NamedTupleClass(1, 2, 3) # 생성한 네임드 튜플 클래스로 오브젝트 생성
print(nt)
print(nt.y)

[결과]
NamedTuple(x=1, y=2, z=3)
2
  • [예제] typing 모듈을 사용한 네임드 튜플 (named tuple)
import typing

class Point(typing.NamedTuple) :
    x : int
    y : int
    z : int

p = Point(1, 2, 3)
print(p)
print(p.z)  # 이름으로 값 조회
print(p[1]) # 배열 순서로 값 조회

[결과]
Point(x=1, y=2, z=3)
3
2

 

II. 리스트(list)

  • 리스트는 object 클래스를 자료형으로 인식하여 파이썬 객체를 원소로 가질 수 있으며, 변경, 삭제, 추가 가능
  • 리스트로 객체를 만드는 방법은 대괄호(“[“, “]”)를 사용하거나 생성자를 사용
  • [예제] 리스트
list1 = [1, 2, 3]
list2 = [4, 5]

list1.append(list2) # 기존 객체에 리스트를 원소로 추가
print("append 적용: ",list1)

list1.pop()         # 마지막 원소를 삭제
print("pop 적용: ", list1)

list1.remove(2)     # 원소 중 특정 값을 찾아 삭제
print("remove 적용: ", list1)

list1.extend(list2) # 기존 리스트에 리스트의 원소를 추가(append와 다름)
print("extend 적용: ", list1)

list1 = list1 + list2   # 덧셈 연산 사용 시 새로운 리스트 생성
print("덧셈연산 적용:", list1)

list1.clear()
print("clear 적용: ", list1)

list1.insert(0, 1)      # 특정 인덱스 위치에 원소를 삽입
list1.insert(0, 2)
print("insert 적용: ", list1)

[결과]
append 적용:  [1, 2, 3, [4, 5]]
pop 적용:  [1, 2, 3]
remove 적용:  [1, 3]
extend 적용:  [1, 3, 4, 5]
덧셈연산 적용: [1, 3, 4, 5, 4, 5]
clear 적용:  []
insert 적용:  [2, 1]

 

III. 얕은 복사(swallow copy)와 깊은 복사(deep copy)

  • 파이썬에서는 기본적으로 얕은 복사(swallow copy를 지원
  • 중첩 리스트나 딕셔너리 복사를 위해서는 깊은 복사(deep copy) 사용 필요
  • [예제] 리스트 복사
list1 = [1, 2, 3, 4]
list2 = list1
print("list1 ID: ", id(list1), ", list2 ID : ", id(list2)) # id 값이 동일하므로 얕은 복사 수행 확인

list3 = list1.copy()
print("list1 ID: ", id(list1), ", list3 ID : ", id(list3)) # id 값이 다르므로 새로운 객체 생성 확인

newList = [5, 6, 7]
list1.append(newList)       # 중첩 리스트 만들기 위해 [5, 6, 7] 리스트를 원소로 append
print("append 적용: ", list1)

list1Copy = list1.copy()
print("copy 적용: ", list1Copy)

list1Copy[4][0]= 99        # 마지막 원소의 첫 번째 원소 갱신
print("list1: ", list1)     # 일반적인 복사(Copy) 시 중첩된 리스트는 복사하지 않음
print("list1Copy: ", list1Copy)
print("list1의 4번째 원소(중첩리스트) ID: ", id(list1[4]), "list1Copy의 4번째 원소(중첩리스트) ID", id(list1Copy[4]))

# 중첩 리스트를 모두 새로 만들기 위해 깊은 복사(deep copy) 함수 사용

import copy

list1Deepcopy = copy.deepcopy(list1)
print("list1의 4번째 원소(중첩리스트) ID: ", id(list1[4]), "list1Deepcopy 4번째 원소(중첩리스트) ID", id(list1Deepcopy[4]))

list1Deepcopy[4][1] = 88
print("list1: ", list1)     # 깊은 복사(deep copy) 시 중첩된 리스트도 새로 복사하여 생성
print("list1Deepcopy: ", list1Deepcopy)

[결과]
list1 ID:  20957704 , list2 ID :  20957704
list1 ID:  20957704 , list3 ID :  25715272
append 적용:  [1, 2, 3, 4, [5, 6, 7]]
copy 적용:  [1, 2, 3, 4, [5, 6, 7]]
list1:  [1, 2, 3, 4, [99, 6, 7]]
list1Copy:  [1, 2, 3, 4, [99, 6, 7]]
list1의 4번째 원소(중첩리스트) ID:  25716040 list1Copy의 4번째 원소(중첩리스트) ID 25716040
list1의 4번째 원소(중첩리스트) ID:  25716040 list1Deepcopy 4번째 원소(중첩리스트) ID 26469576
list1:  [1, 2, 3, 4, [99, 6, 7]]
list1Deepcopy:  [1, 2, 3, 4, [99, 88, 7]]

 

IV. Queue 자료구조

  • Queue 메소드 정의 시 객체 상태 확인 empty 함수와 저장된 원소의 상태 확인 getQueue 함수를 작성
  • 원소 정보를 보여줄 때는 다른 리스트 객체를 만들어 반환(원본은 공유하지 않아야 함)
  • 그 다음 Queue 저장소에 원소를 넣는 put 함수와 원소를 꺼내는 get 함수를 작성
class Queue :
    def __init__(self) :
        self._list = []     # 여러 원소 저장을 위한 빈 리스트 할당
    
    def empty(self) :
        return True if len(self._list) == 0 else False # 큐에 원소가 없는 상태 확인
    
    def get(self) :         # 원소를 꺼낼 때는 항상 마지막 원소를 꺼냄
        if len(self._list) == 0 :
            return 0
        else :
            return self._list.pop(-1)
    
    def put(self, value) :  # 원소 저장 시 항상 0 번 째에 값 저장
        return self._list.insert(0, value)
    
    def getQueue(self) :    # 원소 정보를 보여줄 때는 다른 리스트 객체를 만들어 반환
        return self._list.copy()

q = Queue()
print("최초 큐 생성")
print("빈 큐인지 여부: ", q.empty())
print("빈 큐에서 원소 꺼내면: ", q.get())

q.put(10)
print("10 저장 후: ", q.getQueue())
q.put(20)
print("20 저장 후: ", q.getQueue())

q.get()
print("원소 하나 꺼낸 후: ", q.getQueue())

q.put(30)
print("30 저장 후: ", q.getQueue())

q.get()
print("원소 하나 꺼낸 후: ", q.getQueue())

[결과]
초 큐 생성
빈 큐인지 여부:  True
빈 큐에서 원소 꺼내면:  0
10 저장 후:  [10]
20 저장 후:  [20, 10]
원소 하나 꺼낸 후:  [20]
30 저장 후:  [30, 20]
원소 하나 꺼낸 후:  [30]

 
[참고]

  • 잇플, “한 권으로 개발자가 원하던 파이썬 심화 A to Z”, 2019.11

콘텐츠 사용 시 출처 표기 부탁 드리고, 댓글은 큰 힘이 됩니다^^