함수
프로그램이 커지면 같은 로직을 여러 곳에서 작성하게 됩니다. 함수는 로직을 한 번만 작성하고, 이름을 붙이고, 어디서든 사용할 수 있게 해줍니다. 한 곳에서 수정하면 모든 호출에 자동으로 수정이 반영됩니다.
def greet(name):
return f"Hello, {name}!"
print(greet("민준")) # "Hello, 민준!"
print(greet("서연")) # "Hello, 서연!"한 번 작성하고, 어디서든 사용하고, 한 곳에서 수정합니다.
함수 정의하기
def 키워드로 함수 정의를 시작하며, 그 뒤에 이름, 괄호, 콜론, 그리고 들여쓰기된 본문이 옵니다. 함수는 호출하기 전까지 아무것도 하지 않습니다. def로 정의한 다음 이름과 ()로 호출합니다.
def say_hello():
print("Hello!")
say_hello() # 함수 호출매개변수와 인수
매개변수는 함수가 기대하는 입력입니다. 괄호 안에 나열합니다. 함수를 호출할 때 전달하는 값들이 순서대로 매개변수와 매칭됩니다.
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("민준", "Hello") # "Hello, 민준!"
greet("서연", "Hi") # "Hi, 서연!"매개변수 vs 인수
**매개변수(Parameter)**는 함수 정의에서의 이름입니다. **인수(Argument)**는 함수를 호출할 때 실제로 전달하는 값입니다. 실제로는 두 단어가 혼용됩니다. 문서를 읽을 때 차이를 알아두면 됩니다.
기본값
매개변수에 기본값을 줄 수 있습니다. 호출자가 해당 인수를 제공하지 않으면 기본값이 사용됩니다. 기본값이 있는 매개변수는 기본값이 없는 매개변수 뒤에 와야 합니다.
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("민준") # "Hello, 민준!"
greet("민준", "Hi") # "Hi, 민준!"기본값이 있는 매개변수는 기본값이 없는 매개변수 뒤에 와야 합니다.
키워드 인수
함수를 호출할 때 인수에 이름을 붙일 수 있습니다. 이는 매개변수가 많은 함수에서 호출을 읽기 쉽게 만들고, 어떤 순서로든 전달할 수 있게 해줍니다.
def describe_player(name, score, level):
print(f"{name} | Score: {score} | Level: {level}")
describe_player("민준", 87, 5) # 위치
describe_player(name="민준", level=5, score=87) # 키워드, 순서 무관
describe_player("민준", level=5, score=87) # 혼합: 위치 먼저반환값
return은 호출자에게 값을 돌려보냅니다. return이 없으면 함수는 None을 반환합니다. return이 실행되면 함수는 즉시 종료됩니다. 해당 블록에서 그 뒤의 코드는 건너뜁니다.
def add(a, b):
return a + b
result = add(3, 4) # result = 7
print(result)return은 또한 함수를 즉시 종료합니다. 해당 블록에서 그 뒤의 코드는 실행되지 않습니다.
여러 값 반환하기
Python에서는 쉼표로 구분하여 여러 값을 반환할 수 있습니다. 호출자는 이를 튜플로 받으며, 한 줄에서 별도의 이름으로 언패킹할 수 있습니다.
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 7, 1, 9, 4])
print(low, high) # 1 9low, high = ... 구문은 언패킹입니다: Python이 반환된 각 값을 해당 이름에 할당합니다.
스코프
함수 안에서 생성된 변수는 해당 함수 안에서만 존재합니다. 밖에서는 볼 수 없습니다. 모든 함수 밖에서 정의된 변수는 어디서든 볼 수 있지만, 명시적 선언 없이는 함수 안에서 변경할 수 없습니다.
def calculate():
result = 42 # 이 함수에 지역적임
return result
calculate()
print(result) # NameError, result는 여기 밖에 존재하지 않음count = 0
def increment():
global count # 전역을 수정하길 원한다고 선언
count += 1
increment()
print(count) # 1global 사용은 최후의 수단이어야 합니다. 코드를 추론하기 어렵게 만듭니다. 값을 전달하고 반환하는 것을 선호하세요.
*args와 **kwargs
때때로 함수가 몇 개의 인수를 받을지 알 수 없습니다. *args는 임의의 수의 위치 인수를 튜플로 수집합니다. **kwargs는 임의의 수의 키워드 인수를 딕셔너리로 수집합니다. args와 kwargs라는 이름은 관례이며, 중요한 것은 별표입니다.
def total(*args):
return sum(args)
total(1, 2, 3) # 6
total(1, 2, 3, 4, 5) # 15def display(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
display(name="민준", score=87, level=5)일반 매개변수와 섞을 수 있습니다. 일반 매개변수가 먼저 옵니다:
def describe(title, *tags, **metadata):
print(f"{title} | tags: {tags} | meta: {metadata}")
describe("Python intro", "beginner", "python", author="민준", year=2024)도크스트링
도크스트링은 함수 맨 위에 있는 문자열로, 함수가 무엇을 하는지 설명합니다. Python 편집기와 도구는 함수 호출에 마우스를 올렸을 때 도움말을 보여주기 위해 이를 사용합니다. 삼중 따옴표를 사용하고, 간단한 함수에는 한 줄을 작성하세요.
def normalise(value, min_val, max_val):
"""알려진 min과 max를 기준으로 값을 0-1 범위로 스케일링합니다."""
return (value - min_val) / (max_val - min_val)def build_url(base, version, resource, *, secure=True):
"""
API 엔드포인트 URL을 빌드합니다.
완전히 자격이 부여된 URL 문자열을 반환합니다. secure가 False이면
URL은 https 대신 http를 사용합니다.
"""
scheme = "https" if secure else "http"
base = base.replace("https://", "").replace("http://", "")
return f"{scheme}://{base}/{version}/{resource}"이름과 시그니처만으로 자명하지 않은 모든 함수에 대해 도크스트링을 작성하세요.
타입 힌트
타입 힌트는 함수가 어떤 타입을 기대하고 반환하는지 주석을 달 수 있게 해줍니다. Python은 런타임에 강제하지 않지만, 편집기는 이를 사용하여 무언가를 실행하기 전에 실수를 잡아냅니다. 콜론 앞의 ->는 반환 타입을 지정합니다.
def greet(name: str, score: int) -> str:
return f"{name} scored {score}"def log(message: str) -> None:
print(f"[LOG] {message}")def top_scores(scores: list[int], n: int) -> list[int]:
return sorted(scores, reverse=True)[:n]타입 힌트는 선택사항이지만 여러 곳에서 호출될 함수에서 가치가 있습니다. 도구가 검증할 수 있는 문서입니다.
값으로서의 함수
Python의 함수는 문자열이나 숫자와 마찬가지로 값입니다. 변수에 할당하고 다른 함수에 전달할 수 있습니다. 이것이 sorted()가 key= 함수를 받아들이는 방식입니다.
def double(x):
return x * 2
def apply(func, value):
return func(value)
apply(double, 5) # 10함수를 인수로 전달하는 것은 sorted(), map(), filter()와 함께 끊임없이 등장합니다. Lambda, 컴프리헨션, zip 챕터에서도 보게 될 것입니다.
실전에서
함께 작동하는 두 함수: letter_grade는 점수를 문자로 변환하고, summarise는 리스트의 각 점수에 대해 이를 호출합니다:
def letter_grade(score: int) -> str:
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
def summarise(scores: list[int]) -> None:
total = sum(scores)
avg = total / len(scores)
grades = [letter_grade(s) for s in scores]
print(f"Average: {avg:.1f}")
print(f"Grades: {', '.join(grades)}")
summarise([87, 92, 74, 65, 91])
