← 파이썬 강의 목록으로
⚙️
중급 (Intermediate)
*args/**kwargs · lambda · 고차함수 · 클로저

1주차 — 함수 심화

가변 인자(*args, **kwargs), 한 줄 람다, map/filter/sorted with key 같은 고차함수, 그리고 함수 안의 함수가 외부 변수를 기억하는 클로저까지 함수의 표현력을 한 단계 끌어올립니다.

*argslambdahigher-orderclosure
소요 시간
2시간
난이도
📊 중급
선수 조건
🎯 기초 9주차
결과물
표현력 있는 함수형 코드 작성

이 강의에서 배우는 것

  • 1*args, **kwargs 로 가변 인자를 받는다
  • 2람다(lambda) 함수를 사용한다
  • 3고차함수 (map, filter, sorted with key) 를 활용한다
  • 4클로저(closure)의 동작을 이해한다

1. *args, **kwargs

가변 개수의 인자를 받습니다.

python
def add_all(*args):           # args는 튜플
    return sum(args)

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

def info(**kwargs):           # kwargs는 딕셔너리
    for k, v in kwargs.items():
        print(f"{k}: {v}")

info(name="홍길동", age=20)

조합도 가능: def f(a, b, *args, **kwargs):

2. 람다 함수

이름 없는 한 줄 함수. 즉석 사용에 적합.

python
square = lambda x: x * x
print(square(5))   # 25

# 보통 다른 함수의 인자로 전달
nums = [1, 2, 3, 4, 5]
print(list(map(lambda x: x * 2, nums)))  # [2, 4, 6, 8, 10]

3. 고차함수

함수를 인자로 받는 함수.

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

# map: 변환
print(list(map(lambda x: x * x, nums)))      # [1, 4, 9, 16, 25]

# filter: 필터링
print(list(filter(lambda x: x % 2, nums)))   # [1, 3, 5]

# sorted with key
people = [("Alice", 30), ("Bob", 25), ("Charlie", 28)]
people.sort(key=lambda p: p[1])
print(people)

4. 클로저

함수 안에서 정의된 함수가 바깥 변수를 기억.

python
def make_counter():
    count = 0
    def inc():
        nonlocal count    # 바깥 변수 수정 시 nonlocal 필요
        count += 1
        return count
    return inc

c = make_counter()
print(c(), c(), c())   # 1 2 3

5. 자주 하는 실수

  1. *args 의 위치 — 일반 매개변수 뒤, **kwargs 앞
  2. 람다에 너무 많은 로직 — 길어지면 그냥 def. 람다는 한 줄
  3. sorted 와 sort 혼동 — sorted() 는 새 리스트, list.sort() 는 제자리
  4. 클로저에서 nonlocal 누락 — count += 1 만 쓰면 UnboundLocalError

6. FAQ

Q1. 언제 *args 를 써야 하나요?

인자 개수가 정해지지 않을 때. 예: print, max(1, 2, 3, ...).

Q2. 람다와 일반 함수의 성능 차이?

거의 없음. 람다는 가독성·간결함을 위한 문법 설탕.

Q3. 클로저는 어디에 쓰나요?

데코레이터, 콜백, 상태가 있는 함수. 객체 대신 가벼운 대안.

💻 예제 (examples)

실제로 실행해 결과를 확인할 수 있는 예제 코드입니다.

01_args_kwargs.py가변 인자
CODE
def add_all(*args):
    return sum(args)

def info(**kwargs):
    for k, v in kwargs.items():
        print(f"{k}: {v}")

print(add_all(1, 2, 3))
print(add_all(1, 2, 3, 4, 5))
info(name="홍길동", age=20, city="서울")
▶ 실행 결과
6
15
name: 홍길동
age: 20
city: 서울
02_lambda.py람다 함수
CODE
square = lambda x: x * x
add = lambda a, b: a + b
print(square(5))
print(add(3, 4))

nums = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, nums))
print(doubled)
▶ 실행 결과
25
7
[2, 4, 6, 8, 10]
03_higher_order.pymap / filter / sorted
CODE
nums = [1, 2, 3, 4, 5]

print(list(map(lambda x: x * x, nums)))
print(list(filter(lambda x: x % 2, nums)))

people = [("Alice", 30), ("Bob", 25), ("Charlie", 28)]
people.sort(key=lambda p: p[1])
print(people)
▶ 실행 결과
[1, 4, 9, 16, 25]
[1, 3, 5]
[('Bob', 25), ('Charlie', 28), ('Alice', 30)]
04_closure.py클로저와 nonlocal
CODE
def make_counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

c1 = make_counter()
c2 = make_counter()   # 독립적 클로저
print(c1(), c1(), c1())   # 1 2 3
print(c2())               # 1 (c1과 독립)
▶ 실행 결과
1 2 3
1

📝 과제 (exercises)

직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.

과제 1

stats(*nums) — 평균/분산

목표: 가변 인자로 받은 숫자들의 평균과 분산을 출력한다.

요구사항
  • *nums 로 받기
  • 평균과 분산을 한 줄에 출력 (분산은 표본분산 또는 모분산)
입출력 예시
평균: 3.0, 분산: 2.0
정답 코드 펼치기 / 접기
SOLUTION
def stats(*nums):
    n = len(nums)
    if n == 0:
        print("(빈 입력)")
        return
    mean = sum(nums) / n
    var = sum((x - mean) ** 2 for x in nums) / n
    print(f"평균: {mean}, 분산: {var}")

stats(1, 2, 3, 4, 5)
▶ 실행 결과
평균: 3.0, 분산: 2.0
과제 2

학생 점수 정렬 (sorted with key)

목표: 학생 리스트를 점수 내림차순 + 이름 오름차순으로 정렬한다.

요구사항
  • 데이터: [("Alice", 92), ("Bob", 88), ("Charlie", 92), ...]
  • 1차: 점수 내림차순, 2차: 이름 오름차순
입출력 예시
[('Alice', 92), ('Charlie', 92), ('Bob', 88)]
정답 코드 펼치기 / 접기
SOLUTION
students = [("Alice", 92), ("Bob", 88), ("Charlie", 92)]
students.sort(key=lambda s: (-s[1], s[0]))
print(students)
▶ 실행 결과
[('Alice', 92), ('Charlie', 92), ('Bob', 88)]
과제 3

make_counter 호출 카운터

목표: make_counter() 로 만든 카운터 함수를 두 개 호출해 독립성을 보인다.

요구사항
  • make_counter() 가 inc 함수를 반환
  • 각 카운터는 자신만의 count 를 유지
입출력 예시
c1: 1
c1: 2
c2: 1
c1: 3
정답 코드 펼치기 / 접기
SOLUTION
def make_counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

c1 = make_counter()
c2 = make_counter()
print(f"c1: {c1()}")
print(f"c1: {c1()}")
print(f"c2: {c2()}")
print(f"c1: {c1()}")
▶ 실행 결과
c1: 1
c1: 2
c2: 1
c1: 3
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗