너무 좋은 문제의식이야. 실전에서 겪는 혼란 대부분은 "기초 문법은 알지만 실전에선 못 쓰는 이유" 때문이야. 이제부터 그걸 정리해서 단계별로 어떻게 극복할 수 있는지 알려줄게. 특히 정보처리기사 실기 문제와 파이썬 코드 해석에 강해지기 위한 방향으로 설명해줄게.
너가 말한 걸 기반으로 하면 주로 아래 영역에서 막히는 거야:
| 분류 | 예시 | 어떤 착오? |
|---|---|---|
| 고급 문법 등장 | *args, **kwargs, list comprehension, lambda, map/filter/reduce | 생소하거나 동작 순서를 모름 |
| 내장 자료구조 활용 | dict, set, deque, heapq, defaultdict, Counter | 생김새는 아는데 쓰는 이유를 모름 |
| 객체/포인터 개념 | list, dict가 복사되면 왜 원본도 바뀌는지 | 얕은 복사 vs 깊은 복사 모름 |
| 알고리즘적 패턴 | 정렬, 슬라이딩 윈도우, BFS/DFS, 백트래킹 | 구현은 외웠는데 문제에선 못 떠올림 |
| 조건문/루프 흐름 | if not A or B, for i in range(n-1, -1, -1) | 조건 순서나 논리 흐름이 헷갈림 |
print() 찍어가면서 디버깅 해보기lambda x: x[1]arr = [(1, 3), (2, 2), (3, 1)]
arr.sort(key=lambda x: x[1])
print(arr) # [(3, 1), (2, 2), (1, 3)]
생긴 건 생소하지만
x[1]을 기준으로 정렬하는 거야.
lambda는 익명 함수니까def f(x): return x[1]과 같아.
defaultdict(int)from collections import defaultdict
d = defaultdict(int)
d["a"] += 1
print(d) # {'a': 1}
KeyError안 나고 바로0에서 시작함.int()는 기본값 0.
코드 전체 주고 "이 코드 줄줄이 해석해줘" 하면 해줄게.예:
“이 정보처리기사 문제 코드 전체 설명해줘”
→ 코드 전체 붙여주면 한 줄씩 상황 흐름 설명해줄게
예:
“이 문법 처음보는데 해석해줘”
→ 예제 만들고 디버깅 해줄게
내가 자주 등장하는 고급 문법이나 자료구조들을
짧은 예제 + 설명 + 시각화형태로 정리해줄 수 있어
너가 지금 겪고 있는 문제를 같이 분석해보자. 예를 들어 이렇게 해줘:
1. 정보처리기사 실기 문제에서 봤던 코드 중 이해 안 된 거 주기
2. 또는 처음 본 문법을 포함한 줄을 주기
3. 또는 “파이썬 실전에서 자주 쓰는 문법들 정리해줘” 요청
| 전략 | 내용 |
|---|---|
| 고급 문법/자료구조 등장 → 예제로 정복 | 직접 해석 + 예제 + 시각화 |
| 실전 코드 → 줄줄이 해석 | 디버깅하듯이 한 줄씩 설명 |
| 기출 코드 분석 훈련 | 전체 코드의 흐름을 따라가며 분석 |
| 도움 요청 쉽게 하기 | “이 문법 처음봤어”, “이 코드 해석해줘” 하면 됨 |
응! 내가 위에서 예시로 든 것들(lambda, defaultdict, deque, sort(key=...), 얕은 복사 등)은 정보처리기사 실기에서 실전 코드에 자주 등장하는 대표적인 파이썬 문법과 자료구조야. 더 구체적으로 말하면:
| 범주 | 문법/기능 | 실제 등장 예시 |
|---|---|---|
| 1. 정렬 함수 | sorted(), sort(key=...), lambda | 튜플/리스트 정렬 기준 설정 |
| 2. 기본 자료구조 | dict, set, list, tuple | key-value 저장, 중복 제거 |
| 3. 고급 자료구조 | deque, defaultdict, Counter | 큐, 누적 계수, 자동 초기화 |
| 4. 리스트 컴프리헨션 | [x for x in list if 조건] | 필터링, 2차원 배열 초기화 |
| 5. 조건문과 논리 연산 | if not A or B | 우선순위 혼동 주의 |
| 6. 얕은 복사/깊은 복사 | copy(), deepcopy(), [:] | 리스트 복사 실수 주의 |
| 7. 함수 인자 전달 | *args, **kwargs, def f(*a): | 다중 인자 함수 호출 |
| 8. 람다 함수 | lambda x: x[1] | 정렬, 필터링 |
| 9. enumerate / zip | for i, v in enumerate(lst) | 인덱스 + 값 동시에 받기 |
| 10. map / filter / reduce | map(int, input().split()) | 입력 처리 or 값 변환 |
| 11. 예외 처리 | try: ... except: | dict lookup 등에서 사용 |
| 12. 모듈 사용 | heapq, math, collections, itertools | 우선순위 큐, 조합 생성 |
| 13. 슬라이싱 | arr[::-1], arr[1:-1] | 문자열/리스트 처리 |
| 14. 재귀와 DFS/BFS 패턴 | visited, dfs(i) | 연결 요소 찾기, 백트래킹 |
| 15. 클래스 / 구조체 | class Node: | 객체 단위 정렬, 구성 |
defaultdict(int) vs 일반 dictfrom collections import defaultdict
d = defaultdict(int) # 기본값 0으로 자동 생성됨
d['x'] += 1
print(d) # {'x': 1}
KeyErrorlambda x: x[1]을 이용한 정렬arr = [(1, 2), (3, 1), (5, 4)]
arr.sort(key=lambda x: x[1])
print(arr) # [(3, 1), (1, 2), (5, 4)]
deque (양방향 큐)from collections import deque
dq = deque([1, 2, 3])
dq.appendleft(0)
dq.pop()
print(dq) # deque([0, 1, 2])
from collections import deque부터 꼭 필요좋아! 지금부터 정보처리기사 실기에서 자주 등장하는 파이썬 문법 중
1번부터 5번까지를 기초부터 실전 예제, 디버깅 해석까지 줄줄이 설명해줄게.
sorted(), sort(), key=..., lambda| 함수 | 특징 |
|---|---|
sorted(iterable) | 새로운 정렬된 리스트를 리턴 |
list.sort() | 리스트 자체를 제자리 정렬 (in-place) |
key 인자 | 정렬 기준을 지정하는 함수 |
reverse=True | 내림차순 정렬 |
arr = [3, 1, 4, 1, 5]
sorted_arr = sorted(arr) # 정렬된 새로운 리스트 반환
arr.sort(reverse=True) # 원본 arr 자체를 내림차순 정렬
📌 줄줄이 해석:
arr = [3, 1, 4, 1, 5]
# 리스트 arr을 생성한다. 초기 상태: [3, 1, 4, 1, 5]
sorted_arr = sorted(arr)
# sorted()는 arr의 복사본을 정렬해서 새 리스트를 반환한다.
# 원본 arr은 변하지 않고, sorted_arr = [1, 1, 3, 4, 5]
arr.sort(reverse=True)
# arr 리스트 자체를 내림차순으로 바꾼다.
# 실행 후 arr = [5, 4, 3, 1, 1]
key=lambdadata = [(1, 3), (2, 2), (3, 1)]
data.sort(key=lambda x: x[1])
🧠 해설:
(x, y) 형태key=lambda x: x[1]는 두 번째 값을 기준으로 정렬📌 흐름:
data = [(1,3), (2,2), (3,1)]
정렬 기준: x[1] → [3, 2, 1]
정렬 결과: [(3,1), (2,2), (1,3)]
dict, set, list, tupled = {'a': 1, 'b': 2}
d['c'] = 3
print(d['a']) # 1
d.get('x', 0)처럼 .get() 쓰면 기본값 설정 가능s = set([1, 2, 2, 3])
s.add(4)
s.discard(2)
|, &, -lst = [1, 2, 3]
tpl = (1, 2, 3)
list: 변경 가능tuple: 변경 불가 → dict key로 사용 가능deque, defaultdict, Counterfrom collections import deque
q = deque([1, 2, 3])
q.append(4)
q.appendleft(0)
print(q) # deque([0, 1, 2, 3, 4])
q.pop() # → 4
q.popleft() # → 0
from collections import defaultdict
d = defaultdict(int)
d['x'] += 1
print(d) # {'x': 1}
int() (0), list() ([]) 등으로 초기화됨d['y'] += 1을 그냥 써도 에러 안 나고 동작함from collections import Counter
c = Counter("banana")
print(c) # {'a':3, 'b':1, 'n':2}
arr = [x for x in range(5)]
# [0, 1, 2, 3, 4]
evens = [x for x in range(10) if x % 2 == 0]
# [0, 2, 4, 6, 8]
matrix = [[0]*3 for _ in range(4)]
# 4행 3열짜리 0으로 채워진 배열
❗ 실수: [[0]*3]*4는 얕은 복사라 하나만 바뀌어도 전체가 바뀜
if a > 0 and b < 10:
...
and, or, not 연산 순서 주의not A or B → A가 False거나 B가 True이면 Truex = 5
if not x > 10 or x < 7:
print("yes")
🔍 해석:
not x > 10 → not False → TrueTrue or True → 전체가 True → 출력됨if not stack or stack[-1] != val:
stack.append(val)
stack이 비었거나, 맨 위와 값이 다르면 → push| 문법 | 설명 | 예시 |
|---|---|---|
sort(key=lambda x: ...) | 기준 지정 정렬 | 정렬 문제 |
dict, set | 기본 자료구조 | 누적, 중복 제거 |
deque, defaultdict, Counter | 고급 자료구조 | BFS, 누적 카운트 |
| 리스트 컴프리헨션 | 필터링/초기화 | [x for x in ...] |
not A or B | 조건문 우선순위 주의 | if not stack or ... |
원하는 문법에서 더 깊이 파고들 수 있어.
예를 들어 "not A or B는 아직도 헷갈려" 하면 예제 더 들어줄게.
다음은 6번부터 10번까지 문법 해설로 넘어갈까?
정말 잘 물어봤어! 이 부분은 많은 파이썬 초보자들이 헷갈려서 실수하는 부분이고, 정보처리기사 실기나 실전 코딩에서도 자주 트랩으로 나와.
이제부터 [[0]*3]*4가 왜 문제인지, 그리고 왜 [[0]*3 for _ in range(4)]가 안전한지를 디버깅 하듯이 해부해서 설명할게.
matrix = [[0]*3]*4
📌 뜻:
[0]*3 → [0, 0, 0] 리스트 하나를 만들고📌 시각적으로 보면 아래와 같아:
matrix = [
row0 → [0, 0, 0], ← 모든 row가 같은 리스트를 참조
row1 → [0, 0, 0],
row2 → [0, 0, 0],
row3 → [0, 0, 0]
]
✅ 이때, 만약 하나만 바꾸면?
matrix[0][1] = 99
💥 예상은:
[
[0, 99, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
❗ 실제 결과는:
[
[0, 99, 0],
[0, 99, 0],
[0, 99, 0],
[0, 99, 0]
]
왜?
→ row0, row1, row2, row3가 같은 리스트 하나를 가리키고 있어서
→ 하나만 바꿨는데 다 같이 바뀐 것처럼 보임
matrix = [[0]*3 for _ in range(4)]
📌 이건 리스트 컴프리헨션을 이용해서, 0으로 채워진 리스트를 4번 새로 생성하는 코드야.
📌 시각적으로 보면:
matrix = [
row0 → [0, 0, 0], ← 전부 다른 객체
row1 → [0, 0, 0],
row2 → [0, 0, 0],
row3 → [0, 0, 0]
]
✅ 이 상태에서:
matrix[0][1] = 99
👉 결과:
[
[0, 99, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
정상적으로 작동하지? 😊
id()로 비교해보기m1 = [[0]*3]*4
m2 = [[0]*3 for _ in range(4)]
print(id(m1[0]) == id(m1[1])) # True → 같은 객체!
print(id(m2[0]) == id(m2[1])) # False → 서로 다른 객체!
[[0]*3]*4가 안 되는가?잘못된 방식 ([[0]*3]*4) | 올바른 방식 ([[0]*3 for _ in range(4)]) |
|---|---|
| 같은 리스트 4개 참조 | 각각 다른 리스트 생성 |
| 수정 시 전체가 바뀜 | 개별 행만 수정 가능 |
| 얕은 복사 (shallow copy) | 독립 객체 생성 |
리스트 곱하기(
*)는 **"객체를 복사"**할 뿐, 새로운 객체를 만들지 않음.
리스트 컴프리헨션은 **"반복마다 새로운 리스트"**를 만들어줌.
2차원 배열은 반드시 컴프리헨션으로 만들어야 안전해!
좋아! 이번엔 너가 요청한 6번부터 8번까지 — 파이썬 실전에서 자주 헷갈리면서도 정보처리기사 실기나 코딩 문제 풀이에 자주 등장하는 문법들을 차례대로 해부해줄게.
a = [[1, 2], [3, 4]]
b = a
b[0][0] = 99
print(a) # ??
결과:
[[99, 2], [3, 4]]
❗ 왜?
→ a와 b는 **같은 리스트를 가리키는 포인터(참조)**이기 때문이야.
copy()는 얕은 복사다!import copy
a = [[1, 2], [3, 4]]
b = a.copy()
b[0][0] = 99
print(a) # [[99, 2], [3, 4]] → 여전히 영향을 받음
❗ 왜 또 같이 바뀌지?
.copy()는 바깥 리스트만 복사📌 시각화:
a → [ [1, 2], [3, 4] ]
↑ ↑
공유 중 공유 중
b → [ [1, 2], [3, 4] ]
deepcopy()import copy
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)
b[0][0] = 99
print(a) # [[1, 2], [3, 4]] ← a는 영향 없음!
✅ 내부까지 전부 복사하니까 안전해.
| 복사 방법 | 영향 여부 | 설명 |
|---|---|---|
b = a | O | 같은 객체 |
b = a.copy() | △ | 얕은 복사 (1단계만 복사) |
b = deepcopy(a) | ❌ | 완전 독립 복사 |
*args, **kwargsdef f(*args):
for x in args:
print(x)
*args: 여러 개의 인자를 받을 수 있음 → 튜플로 전달됨f(1, 2, 3)
# 출력:
# 1
# 2
# 3
**kwargs (키워드 인자)def f(**kwargs):
for k, v in kwargs.items():
print(k, v)
f(name="Hansun", age=25)
# name Hansun
# age 25
**kwargs: 딕셔너리 형태로 키워드 인자 받음def add(a, b, c):
return a + b + c
params = [1, 2, 3]
print(add(*params)) # 6
params_dict = {'a': 1, 'b': 2, 'c': 3}
print(add(**params_dict)) # 6
*는 리스트나 튜플 → 위치 인자 풀어줌**는 딕셔너리 → 키워드 인자 풀어줌| 구문 | 설명 | 전달 형식 |
|---|---|---|
*args | 여러 개의 값 | 튜플 |
**kwargs | 여러 개의 키=값 | 딕셔너리 |
함수 호출 시 *리스트 | 위치 인자 분해 | |
함수 호출 시 **딕셔너리 | 키워드 인자 분해 |
lambda)f = lambda x: x * 2
print(f(5)) # 10
lambda는 익명 함수 (이름 없는 함수)lambda 인자: 반환값data = [(1, 3), (2, 2), (3, 1)]
data.sort(key=lambda x: x[1])
print(data) # [(3, 1), (2, 2), (1, 3)]
key=lambda x: x[1] → 튜플의 두 번째 값 기준 정렬nums = [1, 2, 3, 4]
doubled = list(map(lambda x: x*2, nums))
print(doubled) # [2, 4, 6, 8]
even = list(filter(lambda x: x%2 == 0, nums))
print(even) # [2, 4]
map(func, iterable) → 각각 변형filter(func, iterable) → 조건 통과하는 것만 남김| 용도 | 사용 예 |
|---|---|
| 정렬 | key=lambda x: x[1] |
| 맵핑 | map(lambda x: x+1, arr) |
| 필터링 | filter(lambda x: x > 0, arr) |
| 항목 | 핵심 내용 | 실수 포인트 |
|---|---|---|
| 얕은/깊은 복사 | copy() vs deepcopy() | 내부 구조가 리스트면 반드시 deepcopy |
*args / **kwargs | 다중 인자 처리 | 호출할 때도 *, ** 써야 함 |
lambda 함수 | 짧은 익명 함수 | 주로 정렬, map, filter에서 사용 |