학습 순서 6번. 새로 작성한 챕터입니다.
원본 수업에서 def 는 세 곳에만 나옵니다 — switchEx.py, testfile.py, class_ex_01.py. 전부 곁다리로 등장할 뿐 함수를 제대로 가르친 적이 없습니다.
함수는 "코드를 짧게 쓰는 요령"이 아니라 생각을 나누는 단위입니다. 데이터 분석 코드는 "읽고 → 정리하고 → 계산하고 → 그린다"의 반복인데, 이걸 함수로 나눠 두지 않으면 100줄짜리 스크립트가 손댈 수 없는 덩어리가 됩니다.
def로 함수를 만들고return으로 값을 돌려준다- 기본값·키워드 인자로 호출을 유연하게 만든다
*args/**kwargs로 개수가 정해지지 않은 인자를 받는다- 지역 변수와 전역 변수의 경계를 안다
- 람다가 정말 필요한 자리를 구분한다
- 독스트링과 타입 힌트로 함수를 설명한다
| 파일 | 내용 |
|---|---|
funcEx1.py | ★ def·return·매개변수, 여러 값 반환, 왜 함수를 쓰나 |
funcEx2.py | 기본값, 키워드 인자, 기본값의 함정 |
funcEx3.py | *args / **kwargs, 언패킹 |
scopeEx.py | 지역·전역, global, 리스트 인자의 특수성 |
lambdaEx.py | 람다, sorted(key=...), map/filter |
docstringEx.py | 독스트링, help(), 타입 힌트 |
test1.py | 연습문제 — 성적 처리 함수 3종 |
python3 step06_function/funcEx1.py전부 입력 없이 실행됩니다.
greet() # 실행한다greet# 함수 자체를 가리킨다 (<function greet at 0x...>)사소해 보이지만 test/class_ex_01.py 의 버그가 정확히 이 차이에서 나왔습니다.
{"+" : cal1.add()} # 값 = add() 를 실행한 결과 ← 즉시 실행된다
{"+" : cal1.add} # 값 = add 함수 그 자체 ← 나중에 부를 수 있다step07 에서 이 파일을 제대로 고칩니다.
defno_return():
print('출력만 한다')
x=no_return()
print(x) # None출력(print)과 반환(return)은 완전히 다릅니다. 초보자가 가장 많이 혼동하는 지점입니다.
print는 화면에 보여 줄 뿐, 값을 남기지 않습니다return은 화면에 아무것도 안 나오지만, 값을 돌려줍니다
계산 결과를 다시 쓰려면 반드시 return 이어야 합니다.
print(add(10, 20) +add(1, 2)) # return 이 있어야 이게 된다
step05에서 만난sort()가None을 돌려준 것도 같은 이야기입니다.sort()는 원본을 바꿀 뿐 반환하지 않습니다.
defbad_append(item, box=[]):
box.append(item)
returnboxbad_append('a') # ['a']bad_append('b') # ['a', 'b'] ← 비어 있길 기대했는데!bad_append('c') # ['a', 'b', 'c']기본값은 함수를 정의할 때 딱 한 번 만들어집니다. 호출할 때마다 새로 만들어지지 않습니다. 그래서 리스트·딕셔너리를 기본값으로 주면 호출 사이에 값이 남습니다.
defgood_append(item, box=None): # 올바른 방법ifboxisNone:
box= []
box.append(item)
returnbox실무에서 정말 자주 나오는 버그라, 파이썬을 오래 쓴 사람도 리뷰에서 지적합니다.
count=10deftry_change():
count=99# 전역 count 를 바꾸는 게 아니다. 새 지역 변수를 만든다print(count) # 99try_change()
print(count) # 10 — 그대로함수 안에서 읽기만 하면 전역 변수가 보입니다. 하지만 대입하는 순간 파이썬은 "이건 지역 변수구나" 하고 판단합니다.
global 키워드로 강제할 수 있지만 되도록 쓰지 마세요. 값이 어디서 바뀌었는지 추적할 수 없게 됩니다. 인자로 받아 return 으로 돌려주는 편이 항상 낫습니다.
단, 리스트는 예외처럼 보입니다.
defadd_item(box):
box.append('추가됨') # 대입이 아니라 내용 변경 → 원본에 반영된다step05 의 복사의 함정과 정확히 같은 원리입니다. = 는 새 이름표를 붙이는 것이고, .append() 는 원래 물건을 건드리는 것입니다.
add=lambdaa, b: a+b# ← 이러려고 만든 문법이 아닙니다변수에 담을 거라면 그냥 def 를 쓰세요. 이름이 있어야 에러 메시지도 친절합니다.
람다가 정말 빛나는 자리는 함수를 인자로 넘길 때입니다.
sorted(students, key=lambdas: s['점수'], reverse=True)
max(students, key=lambdas: s['점수'])key= 는 "무엇을 기준으로 비교할까"를 함수로 받습니다. 이걸 위해 매번 def 를 만드는 건 과합니다.
반면 map / filter 는 컴프리헨션으로 대체할 수 있고, 대개 그쪽이 읽기 좋습니다.
list(map(lambdan: n*10, nums)) # 람다
[n*10forninnums] # 컴프리헨션 — 이쪽이 낫다defbmi(weight, height):
"""체질량지수(BMI)를 계산한다. 매개변수: height (float): 신장 (m 단위. cm 가 아니다) """함수 첫 줄의 """...""" 는 파이썬이 설명서로 인식합니다. help(bmi) 로 볼 수 있고 편집기가 툴팁으로 띄워 줍니다.
step01_base/sumTest.py 에서 "''' 는 사실 문자열인데 주석처럼 쓰인다"고 배웠죠. 함수 첫 줄에 놓으면 버려지지 않고 __doc__ 에 보관됩니다. 같은 문법인데 위치에 따라 역할이 달라집니다.
위 예시에서 "m 단위. cm 가 아니다"는 실제로 중요한 정보입니다. 좋은 독스트링은 코드를 읽어도 알 수 없는 것을 적습니다.
| 증상 | 원인 |
|---|---|
| 함수가 실행 안 됨 | 괄호를 빠뜨림 (greet 대신 greet()) |
결과가 None | print 만 하고 return 을 안 함 |
| 기본값이 계속 쌓임 | 기본값에 리스트·딕셔너리를 씀 |
| 함수 밖 변수가 안 바뀜 | 대입은 지역 변수를 만듦 → return 으로 돌려받기 |
SyntaxError | 기본값 있는 매개변수를 앞쪽에 둠 |
funcEx2.py의bad_append를 세 번 호출해 값이 쌓이는 것을 직접 확인하세요.step04_loop/test2.py의 별 찍기를draw_triangle(n),draw_pyramid(n)함수로 만드세요.step05_datastructure/test1.py의 집계 코드를total(student),average(student),rank(students)함수로 나누세요.- 섭씨↔화씨 변환 함수 두 개를 만들고 독스트링과 타입 힌트를 붙이세요.
help()로 확인하세요. *args를 받아 최댓값과 최솟값의 차이를 돌려주는 함수를 만드세요. 인자가 없을 때는 어떻게 할지도 정하세요.sorted(key=...)로step05의 학생 목록을 ① 이름 가나다순 ② 총점 높은 순 ③ 국어 점수 같으면 영어 점수로 정렬하세요. (③은key=lambda s: (s['국어'], s['영어'])처럼 튜플을 돌려주면 됩니다)