학습 순서 5번. 새로 작성한 챕터입니다.
step01~04 까지 변수 하나에 값 하나를 담았습니다. 하지만 데이터는 언제나 여럿입니다. 학생 100명, 매출 12개월, 로그 백만 줄.
데이터 분석에서 쓰는 DataFrame 은 결국 "딕셔너리를 담은 리스트" 를 다루기 좋게 포장한 것입니다. 이 챕터를 건너뛰면 pandas가 마법처럼 보이고, 마법은 배울 수 없습니다.
- 리스트를 만들고 인덱싱·슬라이싱한다
- 리스트를 바꾸는 메서드(
append·insert·remove·pop·sort)를 쓴다 - 바꿀 수 있는 것(리스트)과 없는 것(튜플) 의 차이를 안다
- 딕셔너리로 "키 → 값" 관계를 다루고, 실제 데이터 모양인 리스트 안의 딕셔너리를 순회한다
- 집합으로 중복을 제거한다
- 컴프리헨션으로 반복문을 한 줄로 줄인다
| 파일 | 내용 |
|---|---|
listEx1.py |
★ 리스트 생성·인덱싱·슬라이싱·중첩 |
listEx2.py |
리스트 메서드, 정렬, 통계, 복사의 함정 |
tupleEx.py |
튜플, 패킹/언패킹, 값 교환 |
dictEx1.py |
★ 딕셔너리 기본, get(), 키/값/쌍 |
dictEx2.py |
★ 순회, 리스트 안의 딕셔너리, 개수 세기 |
setEx.py |
집합, 중복 제거, 집합 연산 |
comprehension.py |
★ 리스트·딕셔너리·집합 컴프리헨션 |
test1.py |
연습문제 — 성적 데이터 집계 |
test2.py |
연습문제 — 단어 빈도 |
python3 step05_datastructure/listEx1.py전부 입력 없이 실행됩니다.
| 기호 | 순서 | 변경 | 중복 | 쓰는 곳 | |
|---|---|---|---|---|---|
| 리스트 | [] |
○ | ○ | ○ | 기본값. 대부분 이걸 씁니다 |
| 튜플 | () |
○ | × | ○ | 바뀌면 안 되는 값, 함수의 여러 반환값 |
| 딕셔너리 | {k:v} |
○ | ○ | 키는 × | 이름으로 찾을 때 |
| 집합 | {} |
× | ○ | × | 중복 제거, 포함 여부 검사 |
nums = [10, 20, 30, 40, 50]
nums[1:3] # [20, 30] ← 3번은 포함 안 됨
nums[:3] # 처음부터
nums[2:] # 끝까지
nums[::-1] # 뒤집기
nums[-1] # 마지막끝을 포함하지 않는다는 규칙이 range·슬라이싱·randrange 에 일관되게 적용됩니다. (randint 만 예외였죠.)
[::-1] 로 뒤집는 건 관용구처럼 자주 씁니다. 문자열에도 됩니다 — 'korea'[::-1] 은 'aerok'.
a = [1, 2, 3]
b = a # 복사가 아니다! 같은 리스트에 이름표를 하나 더 붙인 것
b.append(4)
print(a) # [1, 2, 3, 4] ← a 도 바뀐다파이썬에서 = 는 값을 베끼는 게 아니라 같은 것을 가리키게 합니다. 리스트처럼 내용을 바꿀 수 있는 자료형에서 이게 사고를 냅니다.
d = c[:] # 슬라이싱으로 복사
d = c.copy() # 또는 이렇게listEx2.py 에서 두 경우를 나란히 실행해 확인하세요. 초보자가 가장 오래 헤매는 버그입니다.
student.get('주소') # 없으면 None (KeyError 대신)
student.get('주소', '미입력') # 없으면 기본값step03_controlstmt/switchex/switchEx.py 의 .get(x, 9) 가 바로 이것이었습니다. 그때는 "switch 흉내"로만 봤지만, 실은 딕셔너리에서 안전하게 값을 꺼내는 표준 방법입니다.
students = [
{'이름': '홍길동', '국어': 85, '영어': 73},
{'이름': '김길동', '국어': 90, '영어': 88},
]
for s in students:
print(s['이름'], s['국어'] + s['영어'])CSV 파일, JSON API 응답, 데이터베이스 조회 결과 — 거의 모든 실제 데이터가 이 모양으로 파이썬에 도착합니다. step08 에서 CSV를 읽으면 정확히 이 구조가 나오고, pandas의 DataFrame 도 이걸 표로 포장한 것입니다.
dictEx2.py 를 가장 여러 번 읽으세요.
counter = {}
for c in text:
counter[c] = counter.get(c, 0) + 1"없으면 0에서 시작해서 1 더한다". 빈도 계산에서 계속 나오는 패턴입니다. 표준 라이브러리에 collections.Counter 라는 전용 도구도 있는데, step09 에서 만납니다.
[i ** 2 for i in range(1, 6)]
# ↑ 넣을 값 ↑ 반복뒤부터 읽으세요. "range(1,6)에서 i를 하나씩 꺼내서, i의 제곱을 넣는다".
조건이 붙으면:
[i for i in range(1, 11) if i % 2 == 0] # 걸러내기 — if 가 뒤
['합격' if s >= 60 else '불합격' for s in scores] # 값 고르기 — if 가 앞if 위치가 다릅니다. 뒤에 오면 "거를지 말지", 앞에 오면 "어떤 값을 넣을지"(3항 연산자)입니다. step03 에서 배운 3항 연산자가 여기서 다시 나옵니다.
컴프리헨션은 짧아서 쓰는 것입니다. 한 줄이 길어지거나 조건이 여러 개면 그냥
for문이 읽기 좋습니다.
99999 in big_list # 10만 번 비교 — 느리다
99999 in big_set # 위치를 계산해서 한 번에 — 빠르다setEx.py 마지막 예제입니다. 데이터가 많을 때 "이 값이 있나?"를 자주 물어야 한다면 집합으로 바꿔 두는 것만으로 프로그램이 훨씬 빨라집니다.
| 증상 | 원인 |
|---|---|
| 리스트를 바꿨는데 원본도 바뀜 | b = a 는 복사가 아님 → b = a[:] |
KeyError |
없는 키를 [] 로 꺼냄 → .get() 사용 |
TypeError: 'tuple' object does not support item assignment |
튜플은 바꿀 수 없음 |
{} 가 집합이 아님 |
빈 집합은 set(). {} 는 빈 딕셔너리 |
sort() 결과가 None |
sort() 는 원본을 바꾸고 아무것도 안 돌려줌. 새 리스트가 필요하면 sorted() |
마지막 것이 특히 자주 나옵니다.
nums = [3, 1, 2].sort() # None!
nums = sorted([3, 1, 2]) # [1, 2, 3]listEx2.py의 복사 함정 예제에서b = a를b = a[:]로 바꿔 결과가 달라지는 것을 확인하세요.- 리스트
[5, 3, 8, 1, 9, 2]에서sort()를 쓰지 않고 최댓값을 찾는 코드를for로 작성하세요. test1.py의 과목별 평균 계산을 컴프리헨션 없이for문으로 다시 쓰세요. 어느 쪽이 읽기 좋나요?test1.py에 석차를 추가하세요. 평균이 높은 순으로 1등, 2등, 3등을 출력합니다.test2.py의 단어 빈도에서 3글자 이하 단어는 제외하도록 고치세요.- 두 학급의 학생 이름 리스트가 있을 때, 집합 연산으로 ① 양쪽 모두에 있는 이름 ② 한쪽에만 있는 이름을 구하세요.
step04_loop/test1.py의 "1~100 중 3의 배수 개수"를 컴프리헨션 한 줄로 다시 쓰세요.