본문 바로가기
C.W.K.
Stream
Lesson 04 of 07 · published

함수 — 이름 붙인 동작과 인자 계약

~25 min · function, def, arguments, kwargs, default

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

함수도 값이야

def는 실행 가능한 객체를 만들고 이름에 묶어. 그래서 함수를 변수에 담고, 다른 함수에 넘기고, 함수에서 돌려줄 수 있어. 호출은 새 지역 범위를 만들고 return은 결과와 함께 그 실행을 끝내.

매개변수의 네 자리

/ 앞은 위치로만, * 뒤는 이름으로만 받을 수 있어. 그 사이는 위치나 이름 모두 가능해. 이 구분은 구현 세부인 매개변수 이름을 공개 계약으로 만들지 않거나, 호출부에서 의미를 드러내야 할 때 써.

기본값과 가변 인자

기본값은 함수가 정의될 때 한 번 계산돼. 가변 객체를 기본값으로 두지 말고 None을 표시값으로 써. *args는 남은 위치 인자를 튜플로, **kwargs는 남은 이름 인자를 딕셔너리로 모으며, 호출할 때 별표는 반대로 값을 풀어 줘.

lambda는 한 식에만

lambda는 짧은 콜백이나 정렬 기준처럼 이름이 필요 없는 한 식짜리 함수에 알맞아. 설명이나 여러 단계가 필요하면 def로 이름과 문서화를 주는 편이 나아.

Code

값처럼 넘기고 돌려주는 함수·python
def double(x):
    return x * 2

def triple(x):
    return x * 3

# 인자로
def apply(fn, value):
    return fn(value)

print(apply(double, 5))    # 10
print(apply(triple, 5))    # 15

# dict 에 저장
ops = {"x2": double, "x3": triple}
print(ops["x2"](7))        # 14

# 함수에서 함수 반환
def multiplier(n):
    def inner(x):
        return x * n
    return inner

times_5 = multiplier(5)
print(times_5(10))         # 50
위치 전용과 이름 전용 매개변수·python
# / 가 경계 — 왼쪽은 모두 positional-only
# * 가 경계 — 오른쪽은 모두 keyword-only
def f(p1, p2, /, normal, *, kw1, kw2=10):
    return p1, p2, normal, kw1, kw2

# 유효
print(f(1, 2, 3, kw1=4))                    # (1, 2, 3, 4, 10)
print(f(1, 2, normal=3, kw1=4, kw2=99))     # (1, 2, 3, 4, 99)

# 무효
try:
    f(p1=1, p2=2, normal=3, kw1=4)         # p1/p2 는 positional-only
except TypeError as e:
    print(e)

try:
    f(1, 2, 3, 4)                          # kw1 은 키워드여야
except TypeError as e:
    print(e)
가변 기본값을 피하는 함수·python
# 안 좋음
def bad(item, history=[]):
    history.append(item)
    return history

print(bad("a"))    # ['a']
print(bad("b"))    # ['a', 'b']    <- 공유!

# 좋음
def good(item, history=None):
    if history is None:
        history = []
    history.append(item)
    return history

print(good("a"))   # ['a']
print(good("b"))   # ['b']         <- 새 list
*args와 **kwargs로 모으고 풀기·python
# 시그니처에서 — 추가분 패킹
def summary(name, *items, **flags):
    print(f"name={name}, items={items}, flags={flags}")

summary("a", 1, 2, 3, debug=True, verbose=False)
# name=a, items=(1, 2, 3), flags={'debug': True, 'verbose': False}

# 호출 사이트에서 — 반대 방향 unpack
args = ("a", 1, 2, 3)
kwargs = {"debug": True}
summary(*args, **kwargs)

# 일반 호출 forwarding (decorator 패턴 미리보기)
def wrap(fn):
    def wrapper(*args, **kwargs):
        return fn(*args, **kwargs)
    return wrapper
한 식짜리 함수 lambda·python
# dict list 를 필드로 정렬
people = [{"name": "a", "age": 30}, {"name": "b", "age": 25}]
print(sorted(people, key=lambda p: p["age"]))

# filter + map (보통 컴프리헨션이 이김)
nums = [1, 2, 3, 4, 5]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)               # [2, 4]

# 다중 기준 빠른 sort key
records = [("b", 2), ("a", 3), ("a", 1), ("b", 1)]
print(sorted(records, key=lambda r: (r[0], r[1])))
# [('a', 1), ('a', 3), ('b', 1), ('b', 2)]

External links

Exercise

report(title, /, *items, sep=' | ', limit=None, **meta)를 만들어. title은 위치로만 받고, items는 여러 위치 인자를 모으며, sep와 limit는 이름으로만 받게 해. 제목, limit까지의 항목을 sep로 이은 문자열, meta의 key=value 줄을 출력하고 report('a', 1, 2, 3, limit=2, color='red')를 포함해 네 가지 이상 호출해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.