Python basics | 조건문과 반복문
파이썬 if와 for의 순서: 필터링, 변환, 분기까지 초보자 정리
한 줄 리스트 컴프리헨션에서 if가 앞이나 뒤에 놓이는 이유, 그리고 실제 여러 줄 코드에서는 왜 for가 먼저 실행되는지 예제로 정리했다.
먼저 결론: 조건이 무엇을 검사하는지부터 본다
코드의 모양만 보고 if와 for의 순서를 외우면 금방 헷갈린다. 중요한 것은 조건이 지금 검사하려는 대상이다.
| 검사 대상 | 자연스러운 구조 | 예시 |
|---|---|---|
| 반복 중인 원소 하나 | for 안에서 if | 짝수인지, 글자가 p인지 |
| 리스트 전체의 상태 | if로 먼저 판단한 뒤 for | 목록이 비어 있는지 |
| 반복할 목록 자체 | 조건으로 목록을 고른 뒤 for | VIP 목록 또는 일반 목록 |
일반적인 여러 줄 코드에서 i는 for i in ...가 실행될 때 처음 만들어진다. 그래서 i를 검사하는 if i == ...를 그 위에 둘 수는 없다.
한 줄 문법 네 가지를 여러 줄 코드로 풀어 보기
if가 맨 뒤: 필요한 원소만 남기는 필터링
result = [char for char in "apple" if char == "p"]
# ['p', 'p']
이 문장은 p인 글자만 결과에 넣는다는 뜻이다. 조건에 맞지 않는 a, l, e는 결과에 들어가지 않으므로 길이가 줄어들 수 있다.
result = []
for char in "apple":
if char == "p":
result.append(char)
if-else가 맨 앞: 모든 원소를 넣되 값만 바꾸는 변환
result = ["P" if char == "p" else char for char in "apple"]
# ['a', 'P', 'P', 'l', 'e']
이번에는 어느 글자도 버리지 않는다. p는 P로 바꾸고, 나머지는 원래 글자를 넣는다. 모든 반복에서 append가 한 번씩 실행되므로 결과 길이는 원본과 같다.
result = []
for char in "apple":
if char == "p":
result.append("P")
else:
result.append(char)
in 뒤의 if-else: 반복할 대상 자체를 먼저 고르는 분기
이 경우의 조건은 item 하나가 아니라 customer_type이라는 전체 상태를 검사한다. 처음에는 아래처럼 두 줄로 쓰는 편이 가장 읽기 쉽다.
items = vip_items if customer_type == "VIP" else normal_items
for item in items:
print(item)
한 줄로 표현하면 다음과 같다. 괄호 안에서 먼저 목록 하나를 고르고, 그 다음에 선택된 목록을 순회한다.
result = [item for item in (vip_items if customer_type == "VIP" else normal_items)]
표현식 전체 바깥의 if-else: 작업을 시작할지 결정하는 가드
result = [user + "님" for user in users] if users else ["접속자 없음"]
여기서 if users는 목록 전체가 비어 있는지를 먼저 확인한다. 실제 서비스 코드나 초보자 풀이에서는 아래처럼 풀어 쓰는 편이 더 분명하다.
if users:
result = []
for user in users:
result.append(user + "님")
else:
result = ["접속자 없음"]
필터링한 뒤 for문을 따로 돌리는 경우
질문처럼 먼저 필요한 값만 골라 두고, 그 결과를 다시 for문으로 처리하는 방식도 당연히 쓴다. 고른 결과를 여러 번 사용하거나, 중간 결과에 이름을 붙이는 것이 읽기 쉬울 때 좋다.
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = [number for number in numbers if number % 2 == 0]
for number in even_numbers:
print(number * 10)
# 20
# 40
# 60
다만 결과를 한 번만 쓸 때는 중간 리스트를 만들지 않고 아래처럼 한 번에 처리해도 된다. 둘 중 무엇이 더 좋은지는 “중간 결과를 다시 쓸까?”와 “이름을 붙이면 이해가 쉬워질까?”로 결정하면 된다.
for number in numbers:
if number % 2 == 0:
print(number * 10)
예제 1. 문자열 식을 분리해 계산하기
입력이 "43 + 12"처럼 숫자, 연산자, 숫자의 순서로 주어진다. 처음 떠올릴 수 있는 방식은 공백으로 나누고 연산자에 따라 계산하는 것이다.
def solution(binomial):
box = list(binomial.split(" "))
for char in box:
if box[1] == "+":
answer = int(box[0]) + int(box[2])
elif box[1] == "-":
answer = int(box[0]) - int(box[2])
else:
answer = int(box[0]) * int(box[2])
return answer
여기서 정리할 점
split()의 결과는 이미 리스트다. 따라서 바깥의 list()는 필요 없다.
for char in box에서 char를 전혀 사용하지 않는다. 같은 계산을 세 번 반복할 이유가 없으므로 for문도 필요 없다.
현재 제한에서는 "-" in box도 동작한다. 하지만 “리스트 어딘가에 -가 있는가”보다 “연산자 자리인 1번 칸이 -인가”를 확인하는 box[1] == "-"가 더 정확하다. 음수처럼 -가 다른 의미로 등장하는 입력까지 생각하면 특히 차이가 난다.
def solution(binomial):
a, op, b = binomial.split()
a = int(a)
b = int(b)
if op == "+":
return a + b
if op == "-":
return a - b
return a * b
여기서 a, op, b = binomial.split()은 세 조각을 각각 이름 있는 변수에 담는 언패킹이다. split()은 공백이 여러 개이거나 탭이 있어도 여백을 기준으로 나누므로 split(" ")보다 보통 안전하다. 문자열을 그대로 실행하는 eval()은 외부 입력에서 위험할 수 있으므로 이 글에서는 사용하지 않는다.
예제 2. A와 B를 바꾸고 패턴 찾기
처음에는 문자열을 나누고 바꾼 글자를 리스트에 담은 뒤 다시 합치는 흐름으로 생각할 수 있다. 이 흐름 자체는 좋다. 다만 문자열에 공백이 없다는 점을 놓치면 split() 때문에 한 글자씩 처리되지 않는다.
# 잘못되기 쉬운 부분
for char in myString.split():
...
ans = ",".join(answer)
"ABBA".split()의 결과는 ["ABBA"]다. 공백이 없으므로 통째로 한 조각이 된다. 한 글자씩 꺼내려면 for char in myString처럼 문자열 자체를 순회하면 된다.
",".join(["B", "A", "A", "B"])의 결과는 "B,A,A,B"다. 글자 사이에 쉼표가 끼면 찾으려는 연속 문자열과 달라진다. 빈 문자열로 붙이는 "".join(...)을 사용해야 한다.
def solution(myString, pat):
answer = []
for char in myString:
if char == "A":
answer.append("B")
else:
answer.append("A")
changed = "".join(answer)
return 1 if pat in changed else 0
A와 B만 입력된다는 조건이 있으므로 else에서는 B를 A로 바꿔도 된다. pat in changed는 포함되면 True, 아니면 False를 만든다. 숫자 1 또는 0이 필요하면 int(True)는 1, int(False)는 0이라는 점을 이용할 수 있다.
def solution(myString, pat):
changed = "".join("B" if char == "A" else "A" for char in myString)
return int(pat in changed)
또 하나의 관점은 긴 myString 대신 짧은 pat을 반대로 바꿔 원래 문자열에서 찾는 것이다. A와 B만 있다는 이 문제의 조건에서만 성립하는 변환이다.
def solution(myString, pat):
flipped_pat = "".join("A" if char == "B" else "B" for char in pat)
return int(flipped_pat in myString)
A와 B를 동시에 뒤집는 일이 자주 나온다면 translate()도 쓸 수 있다.
def solution(myString, pat):
changed = myString.translate(str.maketrans("AB", "BA"))
return int(pat in changed)
예제 3. 단순 치환에는 replace()가 가장 직접적이다
def solution(rny_string):
return rny_string.replace("m", "rn")
# "masterpiece" -> "rnasterpiece"
글자 하나를 특정 문자열로 바꾸는 일이라면 replace()가 의도를 가장 바로 보여 준다. 원리를 확인하는 용도로는 아래처럼 컴프리헨션과 join()으로도 쓸 수 있지만, 이 문제에서는 첫 번째 풀이가 더 간단하다.
def solution(rny_string):
return "".join("rn" if char == "m" else char for char in rny_string)
실수 방지 체크리스트
원소 하나를 검사하는가? 그렇다면 보통 for 안에 if를 둔다.
목록 전체 상태나 선택할 목록을 검사하는가? 그렇다면 if로 먼저 결정한 뒤 for를 돌릴 수 있다.
컴프리헨션의 if 위치를 확인한다. 뒤의 if는 필터링, 앞의 if-else는 변환, in 뒤의 if-else는 반복 대상 선택이다.
문자열을 한 글자씩 볼 때는 split()이 필요 없다. for char in text로 바로 순회한다.
연속된 문자열을 만들 때는 "".join()을 쓴다. 쉼표나 공백을 넣은 join은 그 기호도 결과에 포함한다.
같이 보면 좋은 문제
간단한 식 계산하기: split, 언패킹, 정확한 연산자 비교를 연습하기 좋다.
문자열 바꿔서 찾기: 문자열 순회, join, 조건식, in 연산자를 한 번에 복습할 수 있다.
rny_string: replace와 직접 순회의 차이를 비교하기 좋다.
'AI > Coding_Test' 카테고리의 다른 글
| Day 15) 프로그래머스 파이썬 조건 변환과 반복문 5문제 풀 (1) | 2026.07.23 |
|---|---|
| Day 14) 프로그래머스 파이썬 반복문과 리스트 5문제 풀이 (1) | 2026.07.22 |
| Day 13) 프로그래머스 파이썬 슬라이싱 3문제 풀이 (0) | 2026.07.21 |
| Day 12) 프로그래머스 파이썬 슬라이싱 5문제 풀이 (0) | 2026.07.20 |
| Day 10) 프로그래머스 파이썬 문자열 5문제 풀이 (0) | 2026.07.17 |