1. 변하지 않는 튜플
종류 | 구성 | 타입 |
문자열 | 문자 | Immutable |
리스트 | 요소 | Mutable |
딕셔너리 | key:value | Mutable |
문자열은 "a[i]"로 문자에 접근할 수 있지만, Immutable 형식으로 값을 수정할 수 없다.
반면에 리스트, 딕셔너리는 Mutable 형식으로 추가 및 수정을 할 수 있다. 데이터를 처리할 때는 리스트, 딕셔너리를 많이 사용하지만 값을 수정할 수 없은 Immutable한 자료형이 필요할 때가 있다. 따라서 리스트와 유사하지만 값을 바꿀 수 없는 Immutable 버전인 '튜플'이 있다.
t1 = ('a', 'b', 'c', 1, 2, 3)
print(t1, t1[2])
t2 = ("hello",) #하나의 값이면 뒤에 콤마 입력
print(t2)
t3 = "goorm", 'b', "hello", 1, 2, 3 #괄호 생략 가능
print(t3, t3[2])
s1 = list(set([1,2,3])) #다음에 배우게 될 집합 Mutable 타입
t4 = ([1, 2, 3], {"사과":"apple", "포도":"grape"}, ('a', 'b', 'c'), s1) #리스트 내 어떤 값도 가능
print(t4, t4[1])
t4[3][2] = "edit" #중요: 튜플 요소가 Mutable하면 수정할 수 있음
t4[1]["사과"] = "edit"
t4[0][2] = "edit"
print(t4)
- 튜플을 선언하고 초기화 할 때는 소괄호를 사용하고 indexing으로 요소에 접근할 수 있다. 중요한 점은 괄호를 사용하지 않아도 튜플로 초기화된다.
- t2처럼 한 개의 요소만 초기화 하는 튜플은 요소 뒤에 콤마를 꼭 입력해야한다.
- 변수 t3 는 괄호를 사용하지 않고 나열된 값이 튜플로 초기화 된다.
- 튜플 안에 있는 Mutable한 값은 수정할 수 있다. 튜플 자체의 요소는 데이터 초기화와 동시에 정해진 값이기에 수정할 수 없지만, Mutable하다면 요소의 요소를 수정할 순 있다.
** 참고
튜플 내부의 mutable 객체 수정이 가능한 이유?
- 튜플은 불변 객체이다. -> 한 번 생성되면 구성 요소(참조)를 바꿀 수 없다.
- 튜플 안에 있는 객체가 가변적(mutable)이라면 객체의 내부 상태는 바꿀 수 있다.
t = ([1, 2], "hello", 3)
t[0].append(99) # 가능
print(t) # 출력: ([1, 2, 99], 'hello', 3)
t[1] = "world" # 오류 (튜플 요소 자체를 바꾸는 것)
튜플이 저장하는 건 "값"이 아니라 "객체에 대한 참조(주소)"이다. 불변이란 것은 튜플이 가리키는 참조(포인터)를 바꿀 수 없다는 말이지, 그 참조가 가리키는 객체의 내부가 바뀌지 않는 다는 말이 아니다.
t[0] = [1, 2]에서 t[0]은 객체를 가리키는 포인터이다. 포인터는 바꿀 수 없지만, 포인터가 가리키는 리스트의 내부는 바꿀 수 있다.
t1 = ('a', 'b', 'c', 1, 2, 3)
t2 = ("hello",)
t3 = "goorm", 'b', "hello", 1, 2, 3
print(t1 + t2 + t3) #튜플 결합
print(t2 * t3[4]) #곱셈으로 반복 출력
t2 = ("hello",) # 요소가 1개인 튜플
t3 = ("goorm", 'b', "hello", 1, 2, 3)
t3[4] == 2 # 즉, 숫자 2
t2 * t3[4] == ("hello",) * 2
이는 튜플 반복 연산이며, "hello"라는 문자열을 요소로 가진 튜플이 2번 반복된 튜플이 된다.
(1, 2) * 3 → (1, 2, 1, 2, 1, 2)
("a",) * 4 → ('a', 'a', 'a', 'a')
튜플 곱셈의 개념은 튜플 * 정수는 그 튜플을 정수만큼 반복한 튜플을 생성한다. 리스트의 곱셈과 같은 개념이다.
2. 중복과 순서가 없는 집합(Set)
s0 = {3, 2, 5, 1, 8, 4, 3} #집합으로 바로 선언 및 초기화
print(s0, type(s0))
str = "Hello groom!!!"
print(str, type(str))
s1 = set(str)
print(s1, type(s1))
Hello groom!!! <class 'str'>
{'l', 'e', 'g', 'r', ' ', 'o', 'm', 'H', '!'} <class 'set'>
s0와 같이 바로 값을 초기화 할 수 있고, 다른 자료형을 set으로 바꿀 수 있다. set( ) 인자에 문자열, 리스트, 딕셔너리, 튜플 등을 입력할 수 있다. 그럼 값들이 집합으로 변경된다.
특징으로는
- 요소의 순서가 없다.
- 중복되는 값은 1개만 저장된다.
- 딕셔너리는 key만 저장한다.
list = ["a", "a", "c", "groom", 10, 20, 30]
print(list, type(list))
s2 = set(list)
print(s2, type(s2))
dic = {"Anna": 25, "Bob": "doctor"}
print(dic, type(dic))
s3 = set(dic)
print(s3, type(s3))
tp = (190,)
print(tp, type(tp))
s4 = set(tp)
print(s4, type(s4))
['a', 'a', 'c', 'groom', 10, 20, 30] <class 'list'>
{'groom', 'a', 10, 'c', 20, 30} <class 'set'>
{'Anna': 25, 'Bob': 'doctor'} <class 'dict'>
{'Bob', 'Anna'} <class 'set'>
(190,) <class 'tuple'>
{190} <class 'set'>
집합에는 순서와 중복이 없기 때문에 리스트, 튜플에 속한 요소의 중복을 제거하기 위한 필터로 많이 사용된다. 그리고 순서가 없기 때문에 indexing, slicing을 사용할 수 없다.
str = "Hello World!!!"
print(str, type(str))
s0 = set(str)
print(s0, type(s0))
newStr = tuple(s0)
print(newStr)
print(newStr[4])
print(newStr[5:])
print(type(newStr))
Hello World!!! <class 'str'>
{' ', '!', 'o', 'l', 'd', 'e', 'H', 'W', 'r'} <class 'set'>
(' ', '!', 'o', 'l', 'd', 'e', 'H', 'W', 'r')
d
('e', 'H', 'W', 'r')
<class 'tuple'>
set( )으로 다른 자료형을 변환한 것 처럼 튜플은 tuple( )을 사용해서 변환할 수 있다.
3. 집합 함수
함수명 | 사용 구문 |
교집합 | &, intersection() |
합집합 | |, union() |
차집합 | -, difference() |
s1 = set([2,4,6,8,10])
s2 = set([1,2,3,4,5,6,7,8])
interset = s1 & s2 #교집합
print(interset)
print(s1.intersection(s2), s2.intersection(s1)) #함수 사용
print(s1) #s1의 값이 바뀌는 것이 아님
uniset = s1 | s2 #합집합
print(uniset)
print(s1.union(s2))
print(s1) #s1의 값이 바뀌는 것이 아님
difset1 = s1 - s2 #어떤 집합에서 어떤 집합을 빼느냐에 따라 다른 결괏값
difset2 = s2 - s1
print(difset1)
print(difset2)
함수명 | 함수 사용 | 함수 실행 결과 |
add | set.add(a) | 집합 set에 a 값을 추가한다. |
update | set.update([a,b,c, ...]) | 집합 set에 여러 개의 값을 추가한다. |
remove | set.remove(a) | 집합 set에 a 값을 삭제한다. |
s1 = {1, 2, 3, 4}
s1.add("hello")
print(s1)
s1.add(10)
print(s1)
s1.add((1, 2, 3)) # add() 사용 시 튜플, 문자열은 값 하나로 인식
print(s1)
s1.update(["a", "b", "c"]) # set()과 같이 여러 값을 한 요소로 저장
print(s1)
s1.update((11, 12))
print(s1)
s1.update("zyx") # s1.add("hello")와의 차이
print(s1)
s1.remove("hello") # 하나의 값만 제거 가능
print(s1)
{1, 2, 3, 4, 'hello'}
{1, 2, 3, 4, 10, 'hello'}
{1, 2, 3, 4, 10, (1, 2, 3), 'hello'}
{1, 2, 3, 4, 10, (1, 2, 3), 'b', 'c', 'hello', 'a'}
{1, 2, 3, 4, 10, (1, 2, 3), 11, 'b', 12, 'c', 'hello', 'a'}
{1, 2, 3, 4, 10, (1, 2, 3), 11, 'b', 12, 'x', 'c', 'hello', 'a', 'z', 'y'}
{1, 2, 3, 4, 10, (1, 2, 3), 11, 'b', 12, 'x', 'c', 'a', 'z', 'y'}
** set.add()와 set.update()의 동작 차이와 튜플, 리스트 사용 주의점
1. 리스트와 집합은 집합(set)의 원소로 사용할 수 없다.
? 이유 : 리스트와 집합은 mutable(가변) -> 해시 불가능 - > set 내부에 들어갈 수 없음
s = set()
s.add([1,2,3]) # ❌ TypeError 발생
2. 튜플은 set의 원소로 사용할 수 있다.
? 이유 : 튜플은 immutable(불변) → 해시 가능 → 집합의 원소로 사용 가능
s = set()
s.add((1, 2, 3)) # ✅ 정상 작동. 튜플 자체가 하나의 원소로 들어감
3. add( ) vs update( ) 차이점
메서드 | 설명 |
add(x) | x를 하나의 원소로 집합에 추가 |
update(iterable) | iterable의 각 원소를 하나씩 집합에 추가 |
s1 = set()
# add: 튜플 자체가 하나의 원소로 들어감
s1.add((1, 2, 3))
# 결과: s1 = { (1, 2, 3) }
# update: 각 요소가 개별 원소로 들어감
s1.update((11, 12))
# 결과: s1 = { (1, 2, 3), 11, 12 }
즉, add()는 전체 객체를 넣고, update()는 안의 요소들을 꺼내서 각각 넣는다.
⭐ update(['a', 'b', 'c'])처럼 리스트를 사용할 수 있음
update()는 iterable을 받기 때문에 리스트, 튜플, 문자열 등 반복 가능한 자료형을 넘겨줄 수 있음. 리스트 자체는 원소로 넣을 수 없지만 update()로 넘기면 각 요소 'a', 'b', 'c'가 원소로 추가됨.
s1 = set()
s1.update(['a', 'b', 'c'])
# 결과: s1 = { 'a', 'b', 'c' }
'Python' 카테고리의 다른 글
[Python] 딕셔너리(Dictionary) (1) | 2025.07.21 |
---|---|
[Tenserflow] TensorFlow 설치 및 실행 방법(윈도우11, 2025/07/21 기준) (2) | 2025.07.21 |
[Python] Windows에서 python vs python3 명령어 사용 차이(윈도우11에서 명령어 어떤거 사용해야 함? + tensorflow 설치) (1) | 2025.07.21 |
[Python] 리스트의 indexing and slicing, 값 할당 (1) | 2025.07.21 |
[Python] 문자열 함수 (1) | 2025.07.21 |