개발/공부 기록

[파이썬 기초 문법 총정리 #3] 제어문과 함수 완전 정복 — if, while, for, def, lambda (Ch.16~20)

cedis 2026. 3. 8. 02:08

 


들어가며

제어문만큼은 C랑 비슷하겠지 — 라고 생각했는데 아니었다.
for (int i=0; i<n; i++) 같은 게 파이썬에는 없다. 루프가 아예 다른 개념으로 동작한다.
함수도 마찬가지다. *args**kwargs니 하는 게 처음엔 뭔지도 몰랐다.

W3Schools 16~20챕터를 직접 쳐보면서 하나씩 정리했다. 이번 글은 그 기록이다.

시리즈 개요: W3Schools 파이썬 튜토리얼 1~25챕터를 공부한 내용을 묶어 정리합니다.
이번 편은 챕터 16~20: 제어문·함수 전반 — if/elif/else, while, for, def, lambda

1. if / elif / else — 조건문 (Ch.16)

기본 구조는 C랑 거의 같다. 다른 점은 괄호 없이 조건을 쓰고, 블록은 콜론 + 들여쓰기로 구분한다는 것.
else if 대신 elif로 줄여 쓴다.

기본 if / elif / else

# 조건식에 괄호 없음, 블록 끝에 콜론(:) 필수
score = 75

if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")    # 75 >= 70 이므로 여기서 멈춤
else:
    print("F")

# if 블록 안에 내용이 없으면 SyntaxError → pass로 자리 채우기
if score > 90:
    pass    # 나중에 채울 예정, 에러 방지용

삼항 연산자 — 한 줄 if-else

C의 a > b ? a : b에 해당하는 파이썬 문법이다.
어순이 "참일 때 값 if 조건 else 거짓일 때 값"이라 처음엔 좀 낯설다.

# C: max = (a > b) ? a : b;
# Python: 참 if 조건 else 거짓
a, b = 10, 20
max_val = a if a > b else b
print(max_val)    # 20

# 출력에도 바로 쓸 수 있다
print("짝수") if a % 2 == 0 else print("홀수")

논리 연산자 — and / or / not

C의 && || ! 대신 영어 단어를 쓴다. 훨씬 읽기 좋아진다.

C 연산자 Python 연산자 의미 우선순위
! not 결과 반전 1순위 (가장 먼저)
&& and 둘 다 참이어야 참 2순위
|| or 하나만 참이어도 참 3순위 (가장 나중)
age = 25
is_student = False
has_coupon  = True

# not → and → or 순서로 평가됨
if (age < 18 or age > 65) and not is_student or has_coupon:
    print("할인 대상")   # has_coupon=True 이므로 마지막 or에서 참

팁: 복잡한 조건은 ()로 묶어서 명시적으로 그룹핑하는 게 버그를 줄이는 최선이다.


2. while — 조건 기반 반복 (Ch.17)

while 자체는 C랑 거의 똑같다. 다만 파이썬에는 while-else라는 C에 없는 문법이 있다.

break / continue — C와 동일한 역할

i = 0
while i < 10:
    i += 1
    if i == 3:
        continue    # 3은 건너뜀
    if i == 7:
        break       # 7에서 루프 탈출
    print(i)    # 1 2 4 5 6 출력

while-else — C에는 없는 문법

while 뒤에 else를 붙이면, 조건이 거짓이 되어 정상 종료될 때 한 번 실행된다.
break로 탈출하면 else는 실행되지 않는다. 탐색 성공/실패 분기에 유용하다.

# 리스트에서 특정 값 탐색 — break 성공 여부를 else로 판별
nums = [2, 5, 8, 13]
target = 7
i = 0

while i < len(nums):
    if nums[i] == target:
        print(f"찾음: 인덱스 {i}")
        break
    i += 1
else:
    print("없음")   # break가 안 터졌으면 여기 실행 → "없음" 출력

C 출신에게: 이 패턴을 C로 구현하려면 별도 flag 변수를 두거나 goto를 써야 한다. 파이썬 while-else가 훨씬 깔끔하다.


3. for — 순회 기반 반복 (Ch.18)

C의 for (int i=0; i<n; i++)는 파이썬에 없다.
파이썬 for"이터러블(iterable)을 하나씩 꺼내서 순회"하는 개념이다.
리스트, 문자열, 딕셔너리, range, 뭐든 순회 가능한 것이면 다 된다.

기본 for와 range()

# 리스트 순회 — 인덱스 없이 값을 직접
fruits = ["apple", "banana", "cherry"]
for x in fruits:
    print(x)

# 문자열도 순회 가능
for ch in "banana":
    print(ch)

# range() — C의 for(i=0; i<n; i++) 대체
for i in range(5):          # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 10, 2):  # 2, 4, 6, 8 — 2씩 증가, 10 미포함
    print(i)

enumerate() / zip() — 실전에서 필수

인덱스가 필요할 때 C처럼 range(len(lst))를 쓰는 건 파이썬답지 않다.
enumerate()zip()을 쓰면 훨씬 깔끔하다.

# enumerate() — (인덱스, 값) 튜플을 동시에
fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
# 0: apple / 1: banana / 2: cherry

# zip() — 두 리스트를 동시에 순회
names  = ["철수", "영희", "민준"]
scores = [90, 85, 92]
for name, score in zip(names, scores):
    print(f"{name}: {score}점")
# 철수: 90점 / 영희: 85점 / 민준: 92점

for-else — 탐색 실패 감지에 딱 맞다

# break 없이 루프가 정상 끝나면 else 실행
for n in [2, 3, 5, 7]:
    if n == 4:
        print("4 발견")
        break
else:
    print("4 없음")    # break가 안 터졌으므로 실행

알고리즘 팁: 소수 판별, 특정 원소 탐색처럼 "전부 검사 후 실패" 처리가 필요한 코드에서 for-else가 flag 변수 없이 깔끔하게 동작한다.


4. 함수 — def, *args, **kwargs, 스코프 (Ch.19)

함수 기본은 단순한데, 인자 처리 방식이 C보다 훨씬 유연하다.
*args**kwargs를 처음 봤을 때 별이 두 개나 붙은 게 뭔가 싶었는데, 이해하고 나면 굉장히 편리하다.

기본 def — 정의와 호출

# def로 정의, 호출은 함수명()
def greet(name):
    print(f"Hello, {name}!")

greet("철수")    # Hello, 철수!

# 기본값(default) 인자 — 안 넘기면 기본값 사용
def my_country(country="Korea"):
    print(f"I am from {country}")

my_country()           # I am from Korea
my_country("Japan")   # I am from Japan

# 키워드 인자 — 순서 무관, 이름으로 지정
def pet_info(animal, name):
    print(f"I have a {animal} named {name}")

pet_info(name="Buddy", animal="dog")  # 순서 바꿔도 OK

*args — 개수 모르는 위치 인자 → 튜플

# *args: 몇 개를 넘겨도 함수 안에서 튜플로 받는다
def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3))          # 6
print(sum_all(1, 2, 3, 4, 5))    # 15

# 일반 인자 + *args — 일반 인자가 먼저
def greet_many(greeting, *names):
    for name in names:
        print(greeting, name)

greet_many("Hi", "철수", "영희", "민준")

**kwargs — 개수 모르는 키워드 인자 → 딕셔너리

# **kwargs: key=value 형태로 넘기면 함수 안에서 딕셔너리로 받는다
def print_info(**kwargs):
    for key, val in kwargs.items():
        print(f"{key}: {val}")

print_info(name="철수", age=25, city="서울")
# name: 철수 / age: 25 / city: 서울

# 조합 순서: 일반 인자 → *args → **kwargs
def full_example(title, *args, **kwargs):
    print(f"[{title}] args={args}, kwargs={kwargs}")

full_example("테스트", 1, 2, name="Kim", age=30)
# [테스트] args=(1, 2), kwargs={'name': 'Kim', 'age': 30}
문법 받는 형태 호출 방식 내부 타입
def f(a, b) 고정 개수 f(1, 2) 일반 변수
def f(*args) 가변 개수 위치 인자 f(1, 2, 3) tuple
def f(**kwargs) 가변 개수 키워드 인자 f(a=1, b=2) dict

스코프 — LEGB 규칙

파이썬은 변수를 찾을 때 L → E → G → B 순서로 탐색한다.
C는 블록 스코프 + 전역/지역이 전부였는데, 파이썬은 Enclosing(중첩 함수)Built-in이 추가된다.

# LEGB: Local → Enclosing → Global → Built-in
x = "global"

def outer():
    x = "enclosing"
    def inner():
        x = "local"
        print(x)   # "local" — L 에서 바로 찾음
    inner()
    print(x)       # "enclosing" — E

outer()
print(x)           # "global" — G

# 전역 변수 수정: global 키워드 필수
count = 0
def increment():
    global count
    count += 1

# 중첩 함수에서 바깥 함수 변수 수정: nonlocal
def outer2():
    n = 0
    def inner2():
        nonlocal n
        n += 1
    inner2()
    print(n)   # 1

재귀 — base case를 반드시 먼저 써라

파이썬 재귀 기본 한도는 1,000번이다 (C는 스택 크기까지가 한도).
재귀 함수는 반드시 ①종료 조건(base case) ②자기 호출(recursive case) 두 가지 구조여야 한다.

# 팩토리얼 — 재귀의 교과서
def factorial(n):
    if n <= 1:          # ① base case: 멈추는 조건
        return 1
    return n * factorial(n - 1)   # ② recursive case

print(factorial(5))   # 120

# 피보나치 — 메모이제이션 없으면 느리다
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

# 재귀 깊이 확인/변경
import sys
print(sys.getrecursionlimit())   # 기본 1000
sys.setrecursionlimit(2000)      # 늘리기 가능, 너무 크면 Crash 위험

알고리즘 경고: 순수 재귀 피보나치 fib(n)은 O(2ⁿ)이다. n=40 이면 10억 번 이상 호출한다. 실전에서는 @functools.lru_cache나 DP 테이블로 메모이제이션하자.


5. lambda — 이름 없는 한 줄 함수 (Ch.20)

lambdadef로 이름 붙이지 않고 그 자리에서 바로 쓰는 일회용 함수다.
단독으로 쓰는 일은 드물고, map() filter() sorted()에 넣을 때 진짜 빛난다.

문법과 기본 사용

# 문법: lambda 인자 : 반환표현식
# def add(x): return x + 10  →  lambda 한 줄로
add = lambda x: x + 10
print(add(5))        # 15

multiply = lambda a, b: a * b
print(multiply(4, 5))  # 20

map() / filter() / sorted() — 람다의 진짜 무대

nums = [1, 2, 3, 4, 5]

# map() — 모든 요소에 함수 적용
doubled = list(map(lambda x: x * 2, nums))
print(doubled)   # [2, 4, 6, 8, 10]

# filter() — 조건을 만족하는 것만 남기기
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)     # [2, 4]

# sorted() — 커스텀 정렬 기준
students = [("철수", 85), ("영희", 92), ("민준", 78)]
by_score = sorted(students, key=lambda x: x[1])
print(by_score)
# [('민준', 78), ('철수', 85), ('영희', 92)]

# 내림차순은 reverse=True
by_score_desc = sorted(students, key=lambda x: x[1], reverse=True)
print(by_score_desc)
# [('영희', 92), ('철수', 85), ('민준', 78)]
함수 역할 lambda 자리 반환
map(f, lst) 모든 요소 변환 변환 규칙 map object → list()
filter(f, lst) 조건 만족만 통과 필터 조건 (True/False) filter object → list()
sorted(lst, key=) 정렬 정렬 기준 반환 새 리스트

팁: map()·filter() 대신 리스트 컴프리헨션으로 쓰는 게 파이썬 스타일에 더 가깝다.
sorted()key=lambda는 대체재가 없으므로 반드시 익혀두자.


C vs Python 한눈에 비교

이번 챕터에서 C 출신이 가장 헷갈렸던 것들을 정리해봤다.

개념 C Python
조건문 괄호 if (a > b) if a > b:
else if else if (b > c) elif b > c:
삼항 연산자 a > b ? a : b a if a > b else b
논리 연산자 && || ! and or not
인덱스 for for(i=0; i<n; i++) for i in range(n):
배열 순회 for(i=0; i<n; i++) arr[i] for x in arr:
루프 후 처리 flag 변수 별도 선언 for/while ... else:
가변 인자 va_list, va_arg (복잡) *args, **kwargs
인라인 함수 없음 (매크로 등 대체) lambda x: x*2

마무리

제어문은 비슷해 보여도 디테일이 달랐다. 특히 for-else / while-else는 처음 봤을 때 뭔 뜻인지도 몰랐는데,
알고 나면 flag 변수 없이 탐색 결과를 처리하는 깔끔한 방법이었다.

함수 파트는 분량이 꽤 많다. *args/**kwargs는 파이썬 라이브러리 소스를 읽을 때마다 나오는 패턴이라
여기서 확실히 잡아두면 나중에 코드 읽는 게 훨씬 편해진다.

다음 편은 Ch.21~25: 클래스, 상속, 이터레이터, 모듈, 날짜다. 드디어 OOP 파트다.

for-else 하나를 이해하는 데 30분이 걸렸다. 그 30분이 나중에 flag 변수를 없애주는 30분이 됐다.

크래프톤 정글 2주차 | W3Schools Python Ch.16~20 

#크래프톤정글 #파이썬제어문 #파이썬함수 #람다함수 #재귀함수 #Python