기본 콘텐츠로 건너뛰기

방송대 파이썬프로그래밍기초 9강: 컬렉션 선택과 컴프리헨션

0-썸네일-요약노트-파이썬프로그래밍기초-9강

방송대 파이썬프로그래밍기초 9강: 컬렉션 선택과 컴프리헨션

여러 값을 담는다고 해서 같은 그릇을 써야 하는 것은 아니다. 순서가 필요한지, 값을 바꿀지, 중복을 없앨지, 이름으로 값을 찾을지를 먼저 물으면 튜플·문자열·세트·딕셔너리의 선택 기준이 선명해진다. 이 기준으로 슬라이싱과 컴프리헨션을 해석하고, 팰린드롬·금칙어·모스 부호 변환의 처리 흐름까지 재현해 본다.

자료를 담기 전에 네 가지 질문부터 던진다

학습을 위해 ‘수강 과목과 점수를 관리한다’고 가정하자. 점수의 순서가 의미 있고 수정도 해야 한다면 리스트가 자연스럽다. 좌표처럼 순서를 유지하되 한 번 정한 값을 바꾸지 않을 것이라면 튜플이 뜻을 더 잘 드러낸다. 중복 없는 수강 과목만 필요하면 세트가, 과목명으로 점수를 바로 찾아야 한다면 딕셔너리가 알맞다. 자료형은 괄호 모양보다 데이터 사이의 관계와 앞으로 할 연산으로 고른다.

판단 질문튜플문자열세트딕셔너리
순서가 있는가?있음있음순서를 전제하지 않음위치 대신 키로 접근
원소를 직접 바꿀 수 있는가?없음없음추가·삭제 가능항목 추가·변경·삭제 가능
중복을 허용하는가?허용허용허용하지 않음키는 중복 불가, 값은 중복 가능
대표 접근 방식은?인덱스·슬라이스인덱스·슬라이스소속·집합 연산키 조회
적합한 문제바뀌지 않을 순서 자료문자 단위 처리중복 제거·공통 원소이름과 값의 대응

선택 핵심: ‘여러 값을 저장한다’는 공통점만 보지 말고 순서, 변경 가능성, 중복, 조회 기준을 차례로 확인한다. 필요한 연산과 맞지 않는 자료형을 고르면 나중에 변환이나 예외 처리가 늘어난다.

튜플은 순서를 보존하면서 변경 경로를 닫는다

튜플(tuple)은 데이터를 순서 있게 저장하는 불변 시퀀스다. 대괄호를 쓰는 리스트와 달리 보통 소괄호로 표현하며, 원소 하나짜리 튜플은 괄호가 아니라 쉼표로 구분한다. 따라서 (8)은 정수지만 (8,)은 튜플이다.

point = (4, 7)
single = (8,)
season = "summer"
temp, season = 27, "summer"

def cone_result(radius, height):
    volume = 1 / 3 * 3.14 * radius ** 2 * height
    surface = 3.14 * radius ** 2 + 3.14 * radius * height
    return volume, surface

volume, surface = cone_result(3, 5)

쉼표로 묶인 값은 하나의 튜플이 되고, 왼쪽의 여러 변수는 순서대로 그 값을 풀어 받는다. 함수가 두 값을 반환한 것처럼 보여도 실제로는 튜플 하나를 반환하고 언패킹한 것이다. 인덱싱, 슬라이싱, 연결 +, 반복 *, 소속 연산 in은 사용할 수 있고, len·min·max·sum도 조건이 맞는 원소에 적용된다.

그러나 불변이라는 말은 ‘아무 연산도 못 한다’는 뜻이 아니다. count와 index는 튜플을 바꾸지 않고 개수나 위치를 알려 준다. sorted(point)도 원본을 고치지 않고 정렬된 새 리스트를 반환한다. 원소를 더하고 싶다면 기존 튜플과 새 튜플을 +로 연결해 다른 튜플을 만들어야 한다.

radii = (7, 22, 4, 15, 47)
sorted_radii = sorted(radii)       # [4, 7, 15, 22, 47]
extended = radii + (30,)           # 새 튜플
middle = radii[1:4]                # (22, 4, 15)
generated = tuple(x * 2 for x in radii if x < 20)

튜플은 슬라이스를 읽을 수 있지만 radii[1:3] = (9, 10)처럼 부분을 대입할 수 없다. 또 (x * 2 for x in radii)는 튜플이 아니라 값을 요청할 때 생성하는 제너레이터 표현식이다. 튜플이 필요하면 위 코드처럼 tuple(...)로 변환한다.

오개념 교정: 소괄호가 튜플을 만드는 핵심이라고 외우면 한 원소 튜플과 제너레이터에서 틀리기 쉽다. 튜플을 결정하는 핵심 표시는 쉼표이며, 컴프리헨션 결과가 필요할 때는 tuple 생성자를 명시한다.

문자열은 문자로 이루어진 불변 시퀀스다

문자열은 각 원소가 문자로 고정된 불변 시퀀스다. 리스트처럼 인덱싱·슬라이싱·소속 검사·반복을 할 수 있지만 특정 위치에 새 문자를 대입할 수는 없다. 문장을 바꾸는 메소드는 원본을 수정하는 대신 변환된 새 문자열을 반환한다.

하려는 일메소드결과를 읽는 기준
구분자로 나누기split문자열에서 리스트로 바뀜
문자열 원소 연결join구분자가 메소드의 호출자
위치·개수 찾기find, count문자열은 그대로 유지
문자 바꾸기replace바뀐 새 문자열 반환
양쪽 공백 제거strip가운데 공백은 유지
대·소문자 변환upper, lower비교 전에 표기를 통일할 때 유용
문자 구성 검사isdigit, isalpha, isalnum조건에 맞으면 불리언 반환

split과 join은 방향을 반대로 기억하면 쉽다. "I do love python".split(" ")은 공백을 경계로 잘라 리스트를 만들고, "-".join(["I", "do", "love", "python"])은 리스트의 문자열 원소 사이에 하이픈을 끼워 하나의 문자열을 만든다.

heights = [1, 5, 14, 26, 31]
text_heights = [str(value) for value in heights]
height_csv = ",".join(text_heights)
print(height_csv)   # 1,5,14,26,31

join은 문자열 원소를 연결하므로 숫자 리스트를 바로 넘길 수 없다. 먼저 각 숫자를 str로 변환해야 한다. 이 중간 단계가 빠지면 자료형 오류가 난다.

팰린드롬은 원문과 역순을 같은 기준으로 비교한다

팰린드롬(palindrome)은 앞에서 읽은 결과와 뒤에서 읽은 결과가 같은 문자열이다. 슬라이스 [::-1]는 시작과 끝을 생략하고 간격을 -1로 하므로 문자열 전체를 역순으로 읽는다. 입력 조건이 영문자와 숫자뿐이라면 원문과 역순 문자열의 동등 비교로 판정할 수 있다.

sentence = input("문장을 입력하세요: ")
reversed_sentence = sentence[::-1]

if sentence == reversed_sentence:
    print("팰린드롬입니다.")
else:
    print("팰린드롬이 아닙니다.")

level은 역순도 level이므로 참이고, tomato는 역순이 otamot이므로 거짓이다. 판단 순서는 ‘역순 생성 → 동일성 비교 → 결과 선택’이다. 대·소문자나 공백을 허용하는 문제라면 비교 전에 어떤 문자를 무시할지 조건을 먼저 정해야 한다. 정규화 조건 없이 결과만 바꾸면 서로 다른 기준의 문자열을 비교하게 된다.

세트는 위치 대신 소속과 집합 관계를 계산한다

세트(set)는 중복 원소를 허용하지 않고 순서를 전제로 하지 않는 컬렉션이다. 같은 값이 여러 번 들어와도 한 번만 남으므로 중복 제거에 적합하다. 순서가 없기 때문에 인덱싱과 슬라이싱은 사용할 수 없다. 빈 중괄호 {}는 딕셔너리이므로 빈 세트는 반드시 set()으로 만든다.

left = {7, 22, 4, 47}
right = {22, 4, 7, 47}

print(left == right)       # True
print(22 in left)          # True

values = [7, 22, 4, 22, 47]
unique_values = set(values)
even_values = {x for x in values if x % 2 == 0}

세트의 동등 비교는 원소 구성만 보므로 위 두 세트는 같다. len은 중복 제거 후 원소 수를 세고, min·max·sum도 세트의 실제 원소를 대상으로 한다. add는 원소를 추가하고 remove는 원소를 삭제한다.

질문연산자·메소드결과
둘 중 하나에라도 있는가?A | B, A.union(B)합집합
둘 다에 있는가?A & B, A.intersection(B)교집합
A에만 있는가?A - B, A.difference(B)차집합
한쪽에만 있는가?A ^ B대칭차집합
A가 B에 포함되는가?A <= B, A.issubset(B)부분집합 여부
A가 B를 포함하는가?A >= B, A.issuperset(B)상위집합 여부

금칙어 검사는 문자열을 세트 문제로 바꾸면 짧아진다

메일 제목에 금칙어가 하나라도 포함되는지 검사하려면 먼저 문장을 단어로 나누고 표기를 통일한 뒤 세트로 바꾼다. 그 다음 금칙어 세트와의 교집합이 비어 있는지만 보면 된다. 직접 구성한 아래 예시는 각 단계의 자료형 변화를 드러낸다.

blocked = {"free", "prize", "sale"}
title = "Get a FREE prize"

words = title.lower().split()
title_words = set(words)
matched = title_words & blocked

if matched:
    print("스팸입니다.")
else:
    print("스팸이 아닙니다.")
단계값의미
표기 통일·분리["get", "a", "free", "prize"]대문자 FREE를 소문자로 맞추고 단어 경계를 만듦
세트 변환{"get", "a", "free", "prize"}중복보다 소속 여부에 집중
교집합{"free", "prize"}금칙어가 실제로 검출됨
불리언 판정비어 있지 않음스팸 경로 실행

흔한 실패는 원문에서 바로 세트 교집합을 하려는 것이다. 문자열을 set으로 바꾸면 단어가 아니라 문자 집합이 된다. 이 문제의 비교 단위는 ‘문자’가 아니라 ‘단어’이므로 split이 먼저다.

딕셔너리는 위치가 아니라 키로 값을 찾는 매핑이다

딕셔너리(dictionary)는 키와 값의 쌍을 저장하는 매핑이다. 키는 항목을 식별하므로 중복될 수 없지만 서로 다른 키가 같은 값을 가질 수는 있다. in과 not in은 기본적으로 키의 존재 여부를 검사한다. 세트처럼 원소 구성으로 동등성을 비교할 수 있지만, 위치의 크고 작음을 뜻하는 순서 비교와 슬라이싱은 사용할 수 없다.

parts = {"CPU": 950000, "RAM": 420000, "SSD": 195000}

print(parts["RAM"])              # 420000
print(parts.get("GPU", 0))       # 0

parts["GPU"] = 1850000           # 새 항목 추가
parts["SSD"] = 210000            # 기존 값 변경

for name, price in parts.items():
    print(name, price)

대괄호 조회는 키가 없으면 오류가 나지만 get은 지정한 기본값을 반환할 수 있다. keys는 키, values는 값, items는 키·값 쌍을 제공한다. len(parts)는 키·값 쌍의 개수이며, min(parts.keys())와 max(parts.values())처럼 비교 대상을 명시하면 의도가 분명해진다.

조작결과와 주의점
d.get(key, default)키가 없을 때 기본값을 반환하며 딕셔너리는 바꾸지 않음
d.pop(key)지정한 키의 값을 반환하면서 항목을 삭제
d.popitem()선택된 키·값 쌍을 튜플로 반환하면서 삭제
d.clear()모든 항목을 삭제해 빈 딕셔너리로 만듦

딕셔너리 컴프리헨션은 키와 값을 함께 설계한다

세트 컴프리헨션이 원소 하나를 만드는 것과 달리 딕셔너리 컴프리헨션은 콜론을 사이에 둔 키: 값을 만든다. items()로 기존 키와 값을 함께 꺼내면 필터링, 키 변환, 값 계산을 한 표현식으로 나타낼 수 있다.

parts = {
    "CPU": 950000,
    "RAM": 420000,
    "SSD": 195000,
    "GPU": 1850000,
    "Mainboard": 330000,
    "Case": 75000,
    "Power": 98000
}

under_200000 = {
    name: price
    for name, price in parts.items()
    if price <= 200000
}

usd_parts = {
    name.lower(): round(price / 1450)
    for name, price in parts.items()
}

discounted = {
    name: round(price * 0.9)
    for name, price in parts.items()
}

under_200000에는 SSD·Case·Power만 남는다. 판단은 각 항목마다 ‘키와 값 꺼내기 → 가격 조건 검사 → 통과한 키·값 저장’ 순서로 진행된다. usd_parts는 키를 소문자로 바꾸고 1달러를 1,450원으로 가정해 값을 환산하며, discounted는 키를 유지하고 값을 10% 할인한다. 세 결과 모두 새 딕셔너리이므로 원본 parts는 바뀌지 않는다.

컴프리헨션 판독 순서: 먼저 결과 모양이 원소 하나인지 키: 값인지 확인하고, 그다음 반복 대상, 마지막으로 if 조건을 읽는다. 짧게 쓰는 것보다 결과 자료형과 변환 목적을 명확히 하는 것이 우선이다.

모스 부호 변환은 여러 컬렉션이 역할을 나누는 과정이다

영문자와 모스 부호의 대응표에는 딕셔너리가 적합하다. 입력 문자열은 순서를 유지하며 한 문자씩 제공하고, 딕셔너리는 각 문자에 대응하는 부호를 찾는다. 변환 결과를 리스트에 모은 뒤 join으로 연결하면 하나의 출력 문자열이 된다.

morse = {
    "c": "-.-.", "g": "--.", "i": "..", "m": "--",
    "n": "-.", "o": "---", "s": "...", "t": "-"
}

sentence = "coming soon"
result = []

for char in sentence.lower():
    if char == " ":
        result.append("/")
    elif char in morse:
        result.append(morse[char])

print(" ".join(result))

이 예제의 대응표는 coming soon에 필요한 문자만 담은 학습용 축약표다. 문자 c는 키 조회로 -.-.가 되고, 공백은 단어 경계를 보존하기 위해 /로 바뀐다. 없는 문자는 elif char in morse에서 걸러지므로 오류가 나지 않는다. 전체 영문을 처리하려면 같은 방식으로 대응표를 확장해야 한다.

프로그램을 고칠 때는 자료형별 책임을 확인한다. 입력 순서가 깨지면 문자열 반복을, 대응이 틀리면 딕셔너리 항목을, 부호 사이 간격이 틀리면 결과 리스트와 join을 살핀다. 오류를 한꺼번에 찾는 대신 단계의 출력값을 차례로 확인하면 원인을 좁힐 수 있다.

새 문제에서는 저장 관계와 필요한 연산을 함께 점검한다

  1. 비교 단위를 정한다. 문자, 단어, 숫자, 키·값 쌍 중 무엇을 한 원소로 볼지 결정한다.
  2. 관계를 묻는다. 순서, 변경, 중복, 이름 조회 가운데 문제에 필요한 성질을 표시한다.
  3. 대표 연산으로 검산한다. 위치가 필요하면 인덱싱, 공통 항목이면 교집합, 대응 검색이면 키 조회가 가능한지 확인한다.
  4. 변환 전후 자료형을 적는다. split은 문자열에서 리스트로, set은 중복 없는 집합으로, join은 문자열로 결과를 바꾼다.
  5. 원본 변경 여부를 확인한다. 불변 시퀀스와 컴프리헨션은 대개 새 객체를 만들므로 반환값을 저장해야 한다.

예를 들어 ‘제목에 금칙어가 있는가?’는 단어 단위 소속 문제이므로 문자열을 나눈 뒤 세트 교집합을 사용한다. ‘문자를 부호로 바꾸라’는 대응 문제이므로 딕셔너리의 키 조회를 사용한다. 문법보다 문제의 관계를 먼저 읽으면 자료형과 연산이 함께 결정된다.

핵심 개념 정리

불변 시퀀스: 튜플과 문자열은 순서·인덱스·슬라이스를 제공하지만 원소를 직접 바꾸지 않는다. 변환 결과는 새 객체로 받는다.

집합 관계: 세트는 순서 대신 소속과 집합 연산에 집중한다. 중복 제거, 교집합과 부분집합 판정이 핵심이다.

대응 관계: 딕셔너리는 유일한 키로 값을 찾고 바꾼다. 반복 시 키만 필요한지, 값만 필요한지, 쌍이 필요한지 구분한다.

컴프리헨션: 결과 표현, 반복, 조건을 결합해 새 컬렉션을 만든다. 튜플은 생성자, 딕셔너리는 키: 값 형태가 필요하다.

프로그램 연결: 팰린드롬은 역순 비교, 금칙어는 단어 세트의 교집합, 모스 부호는 문자열 순회와 딕셔너리 조회로 해결한다.

최종 사고 순서: 먼저 원소의 단위를 정하고, 순서·변경·중복·키 조회 중 필요한 관계를 고른다. 다음으로 그 관계를 직접 표현하는 연산을 선택하고, 각 단계의 입력 자료형과 출력 자료형을 추적한다. 마지막으로 원본이 바뀌는지 새 객체가 생기는지 확인하면 자료형 선택과 코드 오류를 같은 기준으로 판단할 수 있다.

예상문제 10선

1. ‘순서를 유지해야 하지만 생성 후 원소를 직접 바꾸지 않을 좌표’에 가장 적합한 자료형은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 세트는 순서를 전제로 하지 않아 좌표의 위치 의미를 보존하기 어렵다.
  • ② 정답: 튜플은 순서 있는 불변 시퀀스이므로 고정 좌표의 조건과 맞는다.
  • ③ 오답: 딕셔너리는 키로 값을 찾는 대응 관계가 핵심이며 문제에는 키가 요구되지 않았다.
  • ④ 오답: 문자열은 문자 시퀀스이므로 수치 좌표를 두 원소로 저장하는 목적과 맞지 않는다.

2. 원소 하나인 튜플을 만드는 올바른 표현은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 괄호는 계산 순서를 묶을 뿐 쉼표가 없어 정수 5로 해석된다.
  • ② 오답: 중괄호 안의 원소 하나는 세트를 만든다.
  • ③ 오답: 대괄호는 변경 가능한 리스트를 만든다.
  • ④ 정답: 한 원소 튜플은 원소 뒤 쉼표로 튜플임을 표시한다.

3. data = (7, 2, 9, 2)일 때 sorted(data)의 결과는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: sorted는 원본 튜플을 바꾸지 않고 중복을 유지한 정렬 리스트를 반환한다.
  • ② 오답: 정렬 순서는 맞지만 반환 자료형은 튜플이 아니라 리스트다.
  • ③ 오답: 세트로 바꾸면 중복과 순서 정보가 달라지며 sorted의 결과가 아니다.
  • ④ 오답: 튜플 자체는 불변이지만 새 결과를 만드는 sorted는 사용할 수 있다.

4. 숫자 리스트 [3, 8, 12]를 문자열 "3,8,12"로 만드는 순서로 알맞은 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: split은 이미 존재하는 문자열을 나눌 때 쓰며 현재 입력은 숫자 리스트다.
  • ② 오답: 세트는 순서를 전제로 하지 않고 join은 숫자 원소를 직접 연결하지 못한다.
  • ③ 정답: join의 입력 원소가 모두 문자열이어야 하므로 변환 후 구분자로 연결한다.
  • ④ 오답: 튜플은 슬라이스에 값을 대입할 수 없고 문자열 결합도 해결하지 않는다.

5. word = "level"이 팰린드롬인지 판정하는 조건으로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 대문자 여부를 검사할 뿐 앞뒤 방향의 동일성을 비교하지 않는다.
  • ② 정답: 간격 -1의 슬라이스로 만든 역순과 원문을 비교해 대칭을 판정한다.
  • ③ 오답: 모든 문자열은 자기 자신을 포함하므로 팰린드롬을 구분하지 못한다.
  • ④ 오답: 빈 문자열 여부는 길이를 검사하지만 문자 배열의 대칭과는 다른 조건이다.

6. values = {7, 22, 4, 22, 47}일 때 len(values)의 결과는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 중복된 22는 하나만 남아 실제 원소는 7·22·4·47의 네 개다.
  • ② 오답: 표현에 적힌 횟수를 센 값이며 세트의 중복 제거를 반영하지 않았다.
  • ③ 오답: 서로 다른 원소 하나를 추가로 누락한 계산이다.
  • ④ 오답: 세트에도 len을 적용해 원소 수를 구할 수 있다.

7. 제목 단어 세트와 금칙어 세트에 공통 단어가 하나라도 있는지 직접 확인하는 연산은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 차집합은 한쪽에만 있는 단어를 남겨 공통 금칙어를 직접 보여 주지 않는다.
  • ② 오답: 대칭차집합은 양쪽 중 한쪽에만 있는 단어를 구한다.
  • ③ 오답: 합집합은 모든 단어를 합치므로 금칙어가 실제 제목에도 있었는지 구분하기 어렵다.
  • ④ 정답: 교집합이 비어 있지 않으면 두 세트에 공통인 금칙어가 검출된 것이다.

8. d = {"CPU": 95}에서 없는 키 "GPU"를 오류 없이 0으로 조회하는 표현은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 대괄호 조회는 키가 없을 때 기본값 대신 오류를 발생시킨다.
  • ② 오답: pop은 항목 삭제가 목적이며 기본값 없이 없는 키를 지정하면 오류가 난다.
  • ③ 정답: get의 두 번째 인수 0이 키가 없을 때 반환할 기본값이다.
  • ④ 오답: values는 인수로 키를 받아 조회하는 메소드가 아니다.

9. 모스 부호 변환에서 문자 순서를 보존하며 대응 부호를 찾아 한 문자열로 만드는 흐름은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 문자열이 입력 순서를 제공하고 딕셔너리가 대응을 찾으며 리스트와 join이 출력을 조립한다.
  • ② 오답: 세트 변환은 문자 순서를 잃고 세트는 인덱싱도 지원하지 않는다.
  • ③ 오답: 변환에는 값 정렬이나 불변 튜플의 부분 대입이 필요하지 않다.
  • ④ 오답: 역순과 차집합은 문자·부호의 일대일 대응을 처리하지 못한다.

10. 새로운 컬렉션 문제에서 자료형과 연산을 선택하는 가장 재현 가능한 순서는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 표기부터 고르면 문제의 데이터 관계와 맞지 않는 자료형을 선택할 수 있다.
  • ② 오답: 세트는 순서와 중복 정보를 잃으므로 모든 문제의 공통 출발점이 될 수 없다.
  • ③ 오답: 짧은 문법만 보면 반환 자료형과 원본 변경 여부를 놓쳐 오류가 생긴다.
  • ④ 정답: 데이터 단위와 관계에서 연산을 도출하고 각 단계의 자료형·상태를 확인하는 순서다.

참고 자료와 작성 기준

이 글은 해당 차시 강의자료를 바탕으로 학습 목적에 맞게 재구성한 비공식 학습자료입니다. 개념 관계, 예제와 문제 해설은 학습자의 이해를 돕도록 구성하고 검토했습니다.

  • 작성·편집: 올에이클래스 학습연구팀
  • 주요 근거: 한국방송통신대학교 파이썬프로그래밍기초 9강 ‘컬렉션 2’ 강의자료(2026년)
  • 보충 자료: 외부 보충 자료를 사용하지 않음
  • 편집 원칙: 올에이클래스 편집 정책
  • 최종 내용 검토: 2026-09-07

댓글