본문 바로가기
AI/Coding_Test

Day18)파이썬 if와 for의 순서: 필터링, 변환, 분기까지 초보자 정리

by 거대웅 TitanBear 2026. 7. 28.

Python basics | 조건문과 반복문

파이썬 if와 for의 순서: 필터링, 변환, 분기까지 초보자 정리

한 줄 리스트 컴프리헨션에서 if가 앞이나 뒤에 놓이는 이유, 그리고 실제 여러 줄 코드에서는 왜 for가 먼저 실행되는지 예제로 정리했다.

먼저 결론: 조건이 무엇을 검사하는지부터 본다

코드의 모양만 보고 iffor의 순서를 외우면 금방 헷갈린다. 중요한 것은 조건이 지금 검사하려는 대상이다.

조건이 검사하는 대상에 따른 코드 위치
검사 대상자연스러운 구조예시
반복 중인 원소 하나for 안에서 if짝수인지, 글자가 p인지
리스트 전체의 상태if로 먼저 판단한 뒤 for목록이 비어 있는지
반복할 목록 자체조건으로 목록을 고른 뒤 forVIP 목록 또는 일반 목록

일반적인 여러 줄 코드에서 ifor i in ...가 실행될 때 처음 만들어진다. 그래서 i를 검사하는 if i == ...를 그 위에 둘 수는 없다.

한 줄 문법 네 가지를 여러 줄 코드로 풀어 보기

1

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)
2

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)
3

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)]
4

표현식 전체 바깥의 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()가 가장 직접적이다

문제: 프로그래머스 - rny_string

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)

실수 방지 체크리스트

1

원소 하나를 검사하는가? 그렇다면 보통 for 안에 if를 둔다.

2

목록 전체 상태나 선택할 목록을 검사하는가? 그렇다면 if로 먼저 결정한 뒤 for를 돌릴 수 있다.

3

컴프리헨션의 if 위치를 확인한다. 뒤의 if는 필터링, 앞의 if-else는 변환, in 뒤의 if-else는 반복 대상 선택이다.

4

문자열을 한 글자씩 볼 때는 split()이 필요 없다. for char in text로 바로 순회한다.

5

연속된 문자열을 만들 때는 "".join()을 쓴다. 쉼표나 공백을 넣은 join은 그 기호도 결과에 포함한다.

같이 보면 좋은 문제

간단한 식 계산하기: split, 언패킹, 정확한 연산자 비교를 연습하기 좋다.

문자열 바꿔서 찾기: 문자열 순회, join, 조건식, in 연산자를 한 번에 복습할 수 있다.

rny_string: replace와 직접 순회의 차이를 비교하기 좋다.

한 줄 코드가 낯설 때는 먼저 여러 줄 코드로 풀어 보자. 반복할 원소를 꺼내는 일은 for가 하고, 그 원소를 남길지 바꿀지는 if가 결정한다. 반대로 전체 상태나 반복할 목록을 고르는 조건은 for보다 앞에 둘 수 있다.