안녕하세요~ 저번 시간에
파이썬의 동적 구조에 대해서 살짝 알아보았습니다.
1. 기본형 (Primitive) / 불변형 (Immutable Types)
2. 참조형 (Reference) / 가변형 (Mutable Types)
두가지 유형에 대해서 배워보았습니다.
기본형은 객체가 생성된 후에는 그 값을 바꿀 수 없어서 변수가 바뀔 때 새로운 객체를 만들어 그 객체를 참조하게 됩니다.
a = int(5)
a = int(10)
이러면 a의 값은 5에서 10으로 덮어씌우게 됩니다. 즉 a는 정수 10이 됩니다.
참조형은 객체가 생성된 후에도 그 객체 내부의 내용을 바꿀 수 있습니다. 즉, 객체의 ID는 그대로 유지되면서 값이 수정됩니다.
b = list[5]
b.append(10)
이러면 b의 값은 5랑 10이 들어가 있는 리스트 형태의 배열로 됩니다. 즉 b는 [5, 10]이 됩니다.
이에 대해서 저희 좀 더 알아가 보도록 해요. Reference 타입(리스트, 튜플, 딕셔너리, 집합) 특징과 객체들의 추가/수정/삭제 등등 어떻게 되는지 알려드리겠습니다.
먼저, 참조형 (Reference) / 가변형 (Mutable Types)의 4가지 종류가 있습니다.
: fruits = ["apple", "banana", "cherry", "orange"]
순서 있고, 변경 가능합니다. 이 말은 즉슨 원하는 순서에 값을 불러올 수 있고, 변경도 가능하다는 뜻입니다. 리스트는 가장 자주 쓰이는 자료형입니다.
fruits[0] = apple #이렇게 맨 첫 번째에 있는 apple은 0번째부터 시작합니다. 그 이후에는 1씩 더해서 값이 부여가 됩니다. 이 값을 인덱스(index)라고 부릅니다.
예를 들어서 fruits에 인덱스 번호가 3인 값은 뭐야? 라고 했을 때 그 값은 orange라 할 수 있겠습니다.
인덱스 번호는 -5 ~ 255번까지 있습니다.
양수는 왼쪽에서 오른쪽, 음수는 오른쪽에서 왼쪽으로 '방향'을 표시합니다.
즉 fruits[-1]의 값은 orange입니다.
리스트에 대한 상세 설명입니다.
위키독스 - 리스트 자료형
인덱스 범위를 지정해 잘라낼 수도 있습니다.
fruits = ["apple", "banana", "cherry", "orange"]
print(fruits[1:3]) # ['banana', 'cherry'] (1번 이상 3번 미만)
print(fruits[:2]) # ['apple', 'banana'] (처음부터 2번 전까지)
print(fruits[2:]) # ['cherry', 'orange'] (2번부터 끝까지)
print(fruits[::2]) # ['apple', 'cherry'] (리스트[start : stop : step])
이를 슬라이싱(Slicing)이라고 부르기도 합니다.
: t = (1, 2, 3, 2)
순서 있지만, 변경 불가능합니다. 변경하고 싶으면 리스트로 변환 후 수정. 수정다하면 다시 튜플로 바꿔줘야 합니다.
기본 메서드
count(x) : 해당 값 개수
index(x) : 해당 값 위치
print(t.count(2)) # 2개
print(t.index(1)) # 0번째 위치
: person = {"name": "Alice", "age": 25}
순서 없고, 변경 가능합니다. key :value쌍으로 저장합니다.
: a = {1, 2, 3} b = {3, 4, 5}
순서 없고, 중복도 없습니다. 수학적 집합 연산 가능합니다.
add(x) → 원소 추가
a.add(10)
print(a) # {1, 2, 3, 10}
remove(x) → 원소 삭제 (없으면 에러)
a.remove(2)
print(a) # {1, 3, 10}
*없는 값을 remove()하면 KeyError 발생합니다.
union(b) → 합집합
print(a.union(b)) # {1, 3, 4, 5, 10}
*a | b 와 같은 결과를 얻습니다.
intersection(b) → 교집합
print(a.intersection(b)) # {3}
*a & b 와 같은 결과를 얻습니다.
difference(b) → 차집합
print(a.difference(b)) # {1, 10}
*a - b 와 같은 결과를 얻습니다.
discard(x) → 원소 삭제 (없어도 에러 없음)
a.discard(99) # 없는 원소 삭제 시도
print(a) # {1, 3, 10}
clear() → 모든 원소 삭제
a.clear()
print(a) # set()
이렇게 리스트, 튜플, 딕셔너리, 집합까지 알아보았습니다. 이러한 자료들의 형태를 좀 더 가독성 있게
원하는 방식으로 변환해줄 수도 있습니다. 이를 자료형 변환(Casting)이라고 부릅니다.
print(list("ABC")) # ['A', 'B', 'C']
print(tuple([1, 2, 3])) # (1, 2, 3)
print(set([1, 1, 2, 2])) # {1, 2}
print(dict([("a", 1),("b", 2)])) # {'a':1, 'b':2}
언제 쓸까?
: 데이터 중복 제거 (list → set)
순서 유지/변경
키-값 구조 필요할 때
: 두 변수가 같은 객체(같은 메모리 주소)를 가리키는지 확인해줘야 합니다.
값이 같아도(==) 서로 다른 객체일 수 있기 때문에 is와 ==는 다름
이게 무슨 말인지 예시를 들어보도록 하겠습니다.
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(a == c) # True (값은 같음)
print(a is c) # False (서로 다른 리스트 객체)
print(a is b) # True (같은 객체 참조)
저는 이부분을 이해하는데 좀 오랜 시간이 걸렸습니다. 한마디로 a랑 b는 아예 똑같으니까 a는 b라고 부를 수 있습니다. 이를 영어로 하면 a is b!
a와 c는 [1, 2, 3] 이라는 객체는 똑같아 보이네요... 이를 식으로 나타내면 a == c라고 씁니다.
하지만 a가 c인가요?(a is c) 물었을 때에는 아무리 값이 같아도 다른 리스트 객체이기 때문에 이에 대한 값은 False값이 됩니다.
: 어떤 값이 자료형 안에 포함되어 있는지 확인해줘야 합니다.
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits) # True
print("grape" in fruits) # False
person = {"name": "Alice", "age": 25}
print("name" in person) # True (키 기준 검사)
print("Alice" in person) # False (값은 직접 검사 안 함)
_값 확인하려면 values() 사용
print("Alice" in person.values()) # True