19. 함수 정의와 호출
19.1) 함수란 무엇이며 왜 중요한가
함수(function) 는 특정 작업을 수행하는 이름이 붙은 코드 블록입니다. 여러분은 이미 이 책 전반에서 print(), input(), len(), type() 등 많은 함수를 사용해 왔습니다. 이것들은 Python이 제공하는 내장 함수(built-in functions) 입니다. 이제 여러분은 코드를 정리하고 재사용할 수 있도록, 여러분만의 사용자 정의 함수(custom functions) 를 만드는 방법을 배우게 됩니다.
함수가 중요한 이유
함수는 명확하고 유지보수 가능한 프로그램을 작성하는 데 기본이 됩니다. 함수는 다음과 같은 몇 가지 중요한 이점을 제공합니다:
1. 코드 재사용성(Code Reusability)
함수가 없다면, 어떤 작업을 수행할 때마다 같은 코드를 매번 복사해서 붙여 넣어야 합니다. 여러 곳에서 직사각형의 넓이를 계산하는 상황을 생각해 보세요:
# 함수 없이 - 반복되는 코드
length1 = 5
width1 = 3
area1 = length1 * width1
print(f"Area 1: {area1}")
length2 = 8
width2 = 4
area2 = length2 * width2
print(f"Area 2: {area2}")
length3 = 10
width3 = 6
area3 = length3 * width3
print(f"Area 3: {area3}")Output:
Area 1: 15
Area 2: 32
Area 3: 60이런 반복은 지루하고 실수가 나기 쉽습니다. 넓이를 계산하는 방법을 바꿔야 한다면(예: 단위를 포함하거나 반올림을 적용), 모든 위치를 업데이트해야 합니다. 함수는 코드를 한 번만 작성하고 여러 번 사용할 수 있게 해 주어 이 문제를 해결합니다.
2. 코드 구성(Code Organization)
함수는 큰 프로그램을 더 작고 관리 가능한 조각으로 나눕니다. 각 함수는 하나의 특정 작업만 처리하므로 코드를 이해하고 유지보수하기가 더 쉬워집니다. 수백 줄짜리 긴 스크립트 하나 대신, 관련된 작업을 목적이 명확한 이름의 함수들로 정리할 수 있습니다.
3. 추상화(Abstraction)
함수는 간단한 인터페이스 뒤에 구현 세부 사항을 숨깁니다. len(my_list)를 호출할 때 Python이 어떻게 요소를 세는지 알 필요가 없고, 결과만 얻으면 됩니다. 마찬가지로 여러분의 함수도 복잡한 작업을 간단한 인터페이스로 제공할 수 있어, 코드를 더 쉽게 사용하고 이해할 수 있습니다.
4. 테스트와 디버깅(Testing and Debugging)
함수는 프로그램의 개별 부분을 테스트하기 쉽게 해 줍니다. 각 함수가 독립적으로 올바르게 동작하는지 확인한 뒤 더 큰 프로그램으로 결합할 수 있습니다. 문제가 생기면, 함수는 어디에서 문제가 발생하는지 범위를 좁히는 데 도움이 됩니다.
이 장의 나머지 부분에서는 여러분만의 함수를 정의하는 방법, 함수에 정보를 전달하는 방법, 결과를 되돌려받는 방법, 그리고 함수를 명확하게 문서화하는 방법을 배우게 됩니다. 이러한 기술은 전문적인 Python 코드를 작성하는 데 필수입니다.
19.2) def로 함수 정의하기
Python에서 함수를 만들려면 def 키워드(“define”의 줄임말)를 사용합니다. 함수 정의의 기본 구조는 다음과 같습니다:
def function_name():
# 함수가 호출될 때 실행되는 코드 블록
statement1
statement2
# ... 더 많은 문장각 부분을 나눠 보면 다음과 같습니다:
def: Python에 함수를 정의하고 있음을 알리는 키워드function_name: 여러분이 선택하는 함수 이름(변수 이름과 같은 규칙을 따름)(): 나중에 매개변수(parameters)를 담게 될 괄호(다음 절에서 다룹니다):: 함수 헤더의 끝을 표시하는 콜론- 들여쓴 코드 블록: 함수 본문을 구성하는 문장들(반드시 들여써야 함)
첫 번째 함수
다음은 인사말을 출력하는 간단한 함수입니다:
def greet():
print("Hello!")
print("Welcome to Python functions.")
# Call the function
greet()Output:
Hello!
Welcome to Python functions.함수를 정의하면 Python은 이를 기억하지만, 내부 코드를 즉시 실행하지는 않습니다. 코드는 함수 이름 뒤에 괄호를 붙여 greet()처럼 작성해 함수를 호출(call) 할 때만 실행됩니다.
함수 이름 짓기 규칙
함수 이름은(3장에서 배운 것처럼) 변수 이름과 같은 규칙을 따릅니다:
- 소문자 사용
- 단어는 밑줄로 구분(snake_case)
- 숫자가 아니라 문자나 밑줄로 시작
- 함수가 무엇을 하는지 나타내는 설명적인 이름 사용
# 좋은 함수 이름
def calculate_total():
pass
def get_user_age():
pass
def display_menu():
pass
# 나쁜 함수 이름(하지만 문법적으로는 유효함)
def x(): # 설명적이지 않음
pass
def CalculateTotal(): # 소문자를 사용해야 함
pass
def calc(): # 너무 축약됨
pass참고: 여기서는 pass를 자리 표시자(8장에서 배운 것처럼)로 사용합니다. 아무 동작도 하지 않지만 함수 정의가 문법적으로 완전해지도록 해 줍니다.
함수에는 어떤 코드든 넣을 수 있습니다
함수 본문에는 지금까지 배운 어떤 Python 문장도 넣을 수 있습니다: 변수 대입, 조건문, 반복문, 그리고 다른 함수 호출까지도 가능합니다.
def check_temperature():
temperature = 72
if temperature > 75:
print("It's warm.")
elif temperature > 60:
print("It's comfortable.")
else:
print("It's cool.")
check_temperature()Output:
It's comfortable.여러 함수 정의하기
프로그램에서 필요한 만큼 함수를 정의할 수 있습니다. 각 함수는 독립적이며 별도로 호출할 수 있습니다:
def morning_greeting():
print("Good morning!")
def evening_greeting():
print("Good evening!")
# Call each function
morning_greeting()
evening_greeting()Output:
Good morning!
Good evening!함수 정의 순서
Python에서는 함수를 호출하기 전에 반드시 정의해야 합니다. Python 인터프리터는 코드를 위에서 아래로 읽기 때문에, 함수를 정의하기 전에 호출하려고 하면 오류가 발생합니다:
# WARNING: This will cause a NameError - for demonstration only
# PROBLEM: Function called before it's defined
say_hello() # NameError: name 'say_hello' is not defined
def say_hello():
print("Hello!")올바른 순서는 먼저 정의하고, 그다음 호출하는 것입니다:
# Correct: Define first
def say_hello():
print("Hello!")
# Then call
say_hello()Output:
Hello!하지만 모든 정의가 끝난 뒤에 호출이 일어나는 한, 함수는 파일에서 나중에 정의된 다른 함수를 호출할 수 있습니다:
def first_function():
print("First function")
second_function() # 이것은 괜찮습니다 - 런타임에 호출됨
def second_function():
print("Second function")
# 첫 번째 함수를 호출하기 전에 두 함수 모두 정의되어 있습니다
first_function()Output:
First function
Second function함수는 로컬 스코프를 만듭니다
함수 안에서 생성된 변수는 그 함수 안에서만 존재합니다. 이를 로컬 스코프(local scope) 라고 합니다(21장에서 자세히 다룰 것입니다). 지금은 함수 안에서 일어나는 일은 함수 안에만 남는다는 점만 이해하세요:
def create_message():
message = "This is local"
print(message)
create_message()
# This would cause an error:
# print(message) # NameError: name 'message' is not definedOutput:
This is local변수 message는 함수가 실행되는 동안에만 존재합니다. 함수가 끝나면 변수는 사라집니다.
pass로 비어 있는 함수 만들기
가끔은 함수 구조를 먼저 정의해 두고 나중에 구현하고 싶을 때가 있습니다. 이럴 때 자리 표시자로 pass를 사용합니다:
def future_feature():
pass # TODO: 나중에 이것을 구현하기
# The function exists and can be called, but does nothing
future_feature() # Runs without error, does nothing이는 세부 내용을 채우기 전에 프로그램의 구조를 먼저 스케치할 때 유용합니다.
19.3) 함수 호출과 인자 전달하기
함수를 정의하면 재사용 가능한 코드 조각이 만들어지지만, 함수를 진정으로 강력하게 만들려면 함수에 정보를 전달해야 합니다. 이 정보는 인자(arguments) 를 통해 전달됩니다.
매개변수 vs 인자
계속하기 전에 자주 헷갈리는 두 용어를 정리해 보겠습니다:
- 매개변수(parameter): 함수 정의에서 값을 받아들이는 변수 이름
- 인자(argument): 함수를 호출할 때 실제로 전달하는 값
def greet(name): # 'name' is a parameter
print(f"Hello, {name}!")
greet("Alice") # "Alice" is an argumentOutput:
Hello, Alice!매개변수는 자리 표시자이고, 인자는 그 자리 표시자를 채우는 실제 데이터라고 생각하면 됩니다.
매개변수가 있는 함수 정의하기
입력을 받는 함수를 정의하려면 괄호 안에 매개변수 이름을 추가합니다:
def greet_person(name):
print(f"Hello, {name}!")
print("Nice to meet you.")
# Call with different arguments
greet_person("Alice")
print() # 가독성을 위한 빈 줄
greet_person("Bob")Output:
Hello, Alice!
Nice to meet you.
Hello, Bob!
Nice to meet you.매개변수 name은 함수 내부에서 변수처럼 동작합니다. 함수를 호출할 때마다 name은 여러분이 제공한 인자 값을 갖게 됩니다.
여러 매개변수
함수는 쉼표로 구분하여 여러 매개변수를 받을 수 있습니다:
def calculate_rectangle_area(length, width):
area = length * width
print(f"A rectangle with length {length} and width {width}")
print(f"has an area of {area} square units.")
calculate_rectangle_area(5, 3)
print()
calculate_rectangle_area(10, 7)Output:
A rectangle with length 5 and width 3
has an area of 15 square units.
A rectangle with length 10 and width 7
has an area of 70 square units.여러 매개변수가 있는 함수를 호출할 때는 순서가 중요합니다. 첫 번째 인자는 첫 번째 매개변수로, 두 번째 인자는 두 번째 매개변수로 들어가는 식입니다. 이를 위치 인자(positional arguments) 라고 합니다.
위치 인자
위치 인자에서는 Python이 위치를 기준으로 인자를 매개변수에 매칭합니다:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet("dog", "Buddy")
print()
describe_pet("cat", "Whiskers")Output:
I have a dog.
My dog's name is Buddy.
I have a cat.
My cat's name is Whiskers.순서를 섞으면 예상치 못한 결과가 나옵니다:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# Arguments in wrong order
describe_pet("Buddy", "dog")Output:
I have a Buddy.
My Buddy's name is dog.이는 기술적으로 유효한 Python이지만, 인자가 잘못된 위치에 들어가므로 말이 되지 않는 출력이 만들어집니다.
키워드 인자
위치 관련 오류를 피하려면, 함수를 호출할 때 매개변수 이름을 명시하는 키워드 인자(keyword arguments) 를 사용할 수 있습니다:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# Using keyword arguments - order doesn't matter
describe_pet(animal_type="dog", pet_name="Buddy")
print()
describe_pet(pet_name="Whiskers", animal_type="cat")Output:
I have a dog.
My dog's name is Buddy.
I have a cat.
My cat's name is Whiskers.키워드 인자를 사용하면, Python이 위치가 아니라 이름으로 인자를 매칭하기 때문에 순서가 중요하지 않습니다.
위치 인자와 키워드 인자 섞기
하나의 함수 호출에서 위치 인자와 키워드 인자를 섞어 사용할 수 있지만, 위치 인자가 먼저 와야 합니다:
def create_profile(username, email, age):
print(f"Username: {username}")
print(f"Email: {email}")
print(f"Age: {age}")
# Mixing positional and keyword arguments
create_profile("alice123", email="alice@example.com", age=25)Output:
Username: alice123
Email: alice@example.com
Age: 25하지만 키워드 인자 뒤에 위치 인자를 놓을 수는 없습니다:
# WARNING: This will cause a SyntaxError - for demonstration only
# PROBLEM: Positional argument after keyword argument
# create_profile(username="alice123", "alice@example.com", 25)
# SyntaxError: positional argument follows keyword argument인자 개수는 반드시 맞아야 합니다
함수를 호출할 때는 올바른 개수의 인자를 제공해야 합니다(기본값이 있는 경우는 20장에서 다룹니다):
def add_numbers(a, b):
result = a + b
print(f"{a} + {b} = {result}")
add_numbers(5, 3) # 올바름: 2개 매개변수에 2개 인자Output:
5 + 3 = 8인자를 너무 적게 주거나 너무 많이 주면 오류가 발생합니다:
# WARNING: These will cause TypeErrors - for demonstration only
# PROBLEM: Too few arguments
# add_numbers(5)
# TypeError: add_numbers() missing 1 required positional argument: 'b'
# PROBLEM: Too many arguments
# add_numbers(5, 3, 2)
# TypeError: add_numbers() takes 2 positional arguments but 3 were given표현식을 인자로 사용하기
인자는 단순한 값일 필요는 없으며, 어떤 표현식이든 사용할 수 있습니다:
def display_total(price, quantity):
total = price * quantity
print(f"Total cost: ${total:.2f}")
# Using expressions as arguments
base_price = 10
display_total(base_price * 1.1, 5) # 10% 마크업이 포함된 가격
display_total(15 + 5, 3 * 2) # 두 인자 모두 표현식Output:
Total cost: $55.00
Total cost: $120.00Python은 각 표현식을 먼저 평가한 뒤, 그 결과 값을 함수에 전달합니다.
함수 안에서 함수 호출하기
함수는 다른 함수를 호출할 수 있으며, 이를 통해 작업의 계층 구조를 만들 수 있습니다. 이는 복잡한 작업을 더 작고 관리 가능한 조각으로 나눌 수 있게 해 주는 강력한 기법입니다.
다음은 방 넓이를 계산하는 예시입니다:
def calculate_area(length, width):
return length * width
def display_room_info(room_name, length, width):
area = calculate_area(length, width)
print(f"Room: {room_name}")
print(f"Dimensions: {length} x {width}")
print(f"Area: {area} square feet")
display_room_info("Living Room", 15, 12)Output:
Room: Living Room
Dimensions: 15 x 12
Area: 180 square feet참고: 여기서는 다음 절에서 자세히 살펴볼 return을 사용하고 있습니다. 지금은 calculate_area()가 결과를 호출한 함수로 되돌려 보낸다는 점만 이해하세요.
다음은 함수들이 서로 쌓아 올려지는 또 다른 예시로, 온도 변환 시스템입니다:
def celsius_to_fahrenheit(celsius):
return (celsius * 9/5) + 32
def format_temperature(fahrenheit):
return f"{fahrenheit:.1f}°F"
def display_temperature_conversion(celsius):
fahrenheit = celsius_to_fahrenheit(celsius)
formatted = format_temperature(fahrenheit)
print(f"{celsius}°C equals {formatted}")
# Use the complete conversion system
display_temperature_conversion(25)
display_temperature_conversion(0)
display_temperature_conversion(100)Output:
25°C equals 77.0°F
0°C equals 32.0°F
100°C equals 212.0°F이 예시에서 display_temperature_conversion()은 변환을 수행하기 위해 celsius_to_fahrenheit()를 호출하고, 그다음 결과를 포맷하기 위해 format_temperature()를 호출합니다. 각 함수는 하나의 명확한 책임만 가지므로 코드가 이해하고 유지보수하기 쉽습니다.
19.4) return으로 결과 되돌려 보내기
지금까지의 함수는 (출력처럼) 동작을 수행했지만, 함수를 호출한 코드로 값을 되돌려 보내지는 않았습니다. return 문은 함수가 결과를 계산해 호출자에게 되돌려 보내도록 합니다.
기본 return 문
다음은 값을 계산해 반환하는 간단한 함수입니다:
def add_numbers(a, b):
result = a + b
return result
# Capture the returned value
sum_value = add_numbers(5, 3)
print(f"The sum is: {sum_value}")Output:
The sum is: 8Python이 return 문을 만나면 두 가지 일이 일어납니다:
- 함수는 즉시 실행을 멈춥니다(
return이후 코드는 무시됩니다) - 지정된 값이 호출자에게 전달됩니다
값을 바로 반환하기
반환하기 전에 결과를 변수에 저장할 필요는 없습니다. 표현식을 바로 반환할 수 있습니다:
def multiply(a, b):
return a * b
result = multiply(4, 7)
print(f"4 × 7 = {result}")Output:
4 × 7 = 28이는 더 간결하며, 단순한 계산에서는 선호되는 스타일입니다.
반환된 값 사용하기
함수가 값을 반환하면, 그 값은 다른 어떤 값처럼 어디에서든 사용할 수 있습니다:
def calculate_discount(price, discount_percent):
discount_amount = price * (discount_percent / 100)
return discount_amount
original_price = 100
discount = calculate_discount(original_price, 20)
# Use the returned value in calculations
final_price = original_price - discount
print(f"Original price: ${original_price:.2f}")
print(f"Discount: ${discount:.2f}")
print(f"Final price: ${final_price:.2f}")Output:
Original price: $100.00
Discount: $20.00
Final price: $80.00return은 함수를 즉시 종료합니다
Python이 return 문을 실행하면 함수는 즉시 멈춥니다. return 이후의 코드는 절대 실행되지 않습니다:
def check_age(age):
if age < 18:
return "Minor"
# This line only runs if age >= 18
return "Adult"
print(check_age(15))Output:
Minor이 동작은 함수에서 여러 경우를 처리할 때 유용합니다. 결과를 결정했다면 추가 조건을 확인할 필요 없이 즉시 반환할 수 있습니다.
다음은 return이 어떻게 실행을 멈추는지 보여 주는 예시입니다:
def process_number(n):
if n < 0:
return "Negative"
print("This line runs for non-negative numbers")
if n == 0:
return "Zero"
print("This line runs for positive numbers")
return "Positive"
print(process_number(-5))
print()
print(process_number(0))
print()
print(process_number(10))Output:
Negative
This line runs for non-negative numbers
Zero
This line runs for non-negative numbers
This line runs for positive numbers
Positivereturn이 없는 함수
함수에 return 문이 없거나 값 없이 return만 있다면, 함수는 None을 반환합니다:
def greet(name):
print(f"Hello, {name}!")
# return 문이 없음
result = greet("Alice")
print(f"The function returned: {result}")Output:
Hello, Alice!
The function returned: None마찬가지로 값이 없는 return(값 없이)도 None을 반환합니다:
def process_data(data):
if not data:
return # 조기 종료, None 반환
print(f"Processing: {data}")
return "Success"
result1 = process_data("")
result2 = process_data("some data")
print(f"Result 1: {result1}")
print(f"Result 2: {result2}")Output:
Processing: some data
Result 1: None
Result 2: Success여러 값 반환하기
Python 함수는 쉼표로 구분해 여러 값을 반환할 수 있습니다. Python은 이를 자동으로 튜플(tuple)로 묶습니다(15장에서 배운 것처럼):
def calculate_rectangle(length, width):
area = length * width
perimeter = 2 * (length + width)
return area, perimeter
# Unpack the returned tuple
rect_area, rect_perimeter = calculate_rectangle(5, 3)
print(f"Area: {rect_area}")
print(f"Perimeter: {rect_perimeter}")Output:
Area: 15
Perimeter: 16또한 튜플을 하나의 값으로 받아올 수도 있습니다:
def get_student_info():
name = "Alice"
age = 20
grade = "A"
return name, age, grade
# Capture as a tuple
student = get_student_info()
print(f"Student info: {student}")
print(f"Name: {student[0]}")Output:
Student info: ('Alice', 20, 'A')
Name: Alice서로 다른 타입 반환하기
함수는 상황에 따라 서로 다른 타입의 값을 반환할 수도 있습니다:
def divide(a, b):
if b == 0:
return "Error: Division by zero"
return a / b
result1 = divide(10, 2)
result2 = divide(10, 0)
print(f"10 / 2 = {result1}")
print(f"10 / 0 = {result2}")Output:
10 / 2 = 5.0
10 / 0 = Error: Division by zero이는 동작하긴 하지만, 일반적으로는 오류를 다른 방식으로 처리하는 것이 더 좋은 습관입니다(Part VII에서 예외를 배웁니다). 지금은 함수가 서로 다른 타입을 반환할 수 있다는 점을 이해하되, 종종 일관성을 유지하는 편이 더 명확하다는 것도 함께 알아 두세요.
19.5) Docstring으로 함수 문서화하기
프로그램이 커지고 더 많은 함수를 만들게 되면, 각 함수가 무엇을 하는지 문서화하는 일이 매우 중요해집니다. Python은 docstring(documentation strings)을 사용해 함수를 문서화하는 내장 방식을 제공합니다.
Docstring이란?
docstring은 함수(또는 모듈, 클래스, 메서드)의 첫 번째 문장으로 나타나는 문자열 리터럴입니다. docstring은 함수가 무엇을 하는지, 어떤 매개변수를 받는지, 무엇을 반환하는지 설명합니다. docstring은 여러 줄에 걸쳐 쓸 수 있도록 삼중 따옴표(""" 또는 ''')로 감쌉니다.
def calculate_area(length, width):
"""Calculate the area of a rectangle.
Takes the length and width of a rectangle and returns the area.
"""
return length * widthDocstring이 중요한 이유
docstring은 다음과 같은 여러 중요한 목적을 가집니다:
- 자기 문서화(Self-Documentation): 코드를 분석하지 않아도 함수가 무엇을 하는지 설명해 줍니다
- IDE 지원(IDE Support): 많은 개발 도구가 함수를 사용할 때 docstring을 툴팁으로 표시합니다
- help() 함수(help() Function): Python 내장
help()함수는 docstring을 출력합니다 - 전문적인 관행(Professional Practice): 잘 문서화된 코드는 유지보수하고 다른 사람과 공유하기가 쉽습니다
기본 Docstring 형식
간단한 함수라면 한 줄짜리 docstring이면 충분합니다:
def greet(name):
"""Print a personalized greeting."""
print(f"Hello, {name}!")
# Access the docstring
print(greet.__doc__)Output:
Print a personalized greeting.docstring은 함수가 무엇을 하는지에 대한 간결한 설명이어야 하며, “This function calculates...” 같은 설명형 문장이 아니라 “Calculate...”, “Return...”, “Print...” 같은 명령형으로 쓰는 것이 좋습니다.
여러 줄 Docstring
더 복잡한 함수에서는 다음을 포함하는 여러 줄 docstring을 사용하세요:
- 첫 줄에 짧은 요약
- 빈 줄
- 더 자세한 설명
- 매개변수에 대한 정보
- 반환 값에 대한 정보
def calculate_discount(price, discount_percent):
"""Calculate the discounted price.
Takes an original price and a discount percentage, then returns
the amount of discount that should be applied.
Parameters:
price (float): The original price before discount
discount_percent (float): The discount percentage (0-100)
Returns:
float: The discount amount in the same currency as the price
"""
return price * (discount_percent / 100)
# Use help() to see the full docstring
help(calculate_discount)Output:
Help on function calculate_discount in module __main__:
calculate_discount(price, discount_percent)
Calculate the discounted price.
Takes an original price and a discount percentage, then returns
the amount of discount that should be applied.
Parameters:
price (float): The original price before discount
discount_percent (float): The discount percentage (0-100)
Returns:
float: The discount amount in the same currency as the priceDocstring 관례
Python에는 docstring 작성에 대한 확립된 관례가 있습니다(PEP 257에 문서화되어 있습니다). 핵심 가이드는 다음과 같습니다:
1. 삼중 큰따옴표 사용: """docstring"""
def good_example():
"""This follows the convention."""
pass
def also_valid():
'''This works but is less common.'''
pass2. 한 줄 docstring은 한 줄에 들어가야 합니다:
def add(a, b):
"""Return the sum of a and b."""
return a + b3. 여러 줄 docstring은 요약 줄 다음에 빈 줄을 둬야 합니다:
def process_order(order_id, items):
"""Process a customer order and update inventory.
This function validates the order, checks inventory availability,
calculates the total cost, and updates the inventory database.
Parameters:
order_id (str): Unique identifier for the order
items (list): List of item dictionaries with 'product' and 'quantity'
Returns:
dict: Order summary with 'total', 'status', and 'confirmation_number'
"""
# 여기 함수 구현
pass매개변수와 반환 값 설명하기
매개변수와 반환 값을 문서화할 때는 다음을 구체적으로 작성하세요:
- 매개변수 이름: 함수의 실제 매개변수 이름과 일치해야 합니다
- 타입(Types): 어떤 데이터 타입이 기대되는지(43장에서 타입 힌트를 배웁니다)
- 목적(Purpose): 그 매개변수가 무엇에 쓰이는지
- 반환 값(Return value): 함수가 무엇을, 어떤 조건에서 반환하는지
def find_student(student_id, students):
"""Find a student by ID in a list of student records.
Parameters:
student_id (int): The unique ID number of the student to find
students (list): List of student dictionaries, each containing 'id' and 'name'
Returns:
dict: The student dictionary if found, None if not found
"""
for student in students:
if student['id'] == student_id:
return student
return None여러 반환 타입을 가진 함수의 Docstring
상황에 따라 서로 다른 타입을 반환할 수 있는 함수라면, 가능한 모든 경우를 문서화하세요:
def safe_divide(a, b):
"""Divide two numbers with error handling.
Parameters:
a (float): The dividend
b (float): The divisor
Returns:
float: The quotient if division is successful
str: An error message if b is zero
"""
if b == 0:
return "Error: Cannot divide by zero"
return a / bDocstring에 접근하기
함수의 docstring은 세 가지 방법으로 접근할 수 있습니다:
1. __doc__ 속성 사용:
def example():
"""This is an example function."""
pass
print(example.__doc__)Output:
This is an example function.2. help() 함수 사용:
def calculate_bmi(weight, height):
"""Calculate Body Mass Index.
Parameters:
weight (float): Weight in kilograms
height (float): Height in meters
Returns:
float: BMI value
"""
return weight / (height ** 2)
help(calculate_bmi)Output:
Help on function calculate_bmi in module __main__:
calculate_bmi(weight, height)
Calculate Body Mass Index.
Parameters:
weight (float): Weight in kilograms
height (float): Height in meters
Returns:
float: BMI value3. 대화형 개발 환경에서: 대부분의 IDE와 코드 에디터는 함수 이름에 마우스를 올리거나 입력할 때 docstring을 툴팁으로 보여 줍니다.
Docstring을 언제 작성해야 할까
다음에는 docstring을 작성해야 합니다:
- 모든 공개 함수(All public functions): 프로그램의 다른 부분이나 다른 프로그래머가 사용하도록 만들어진 함수
- 복잡한 함수(Complex functions): 이름과 매개변수만으로 목적이나 동작이 바로 드러나지 않는 함수
- 명확하지 않은 매개변수가 있는 함수(Functions with non-obvious parameters): 매개변수 이름만으로 기대되는 값이 충분히 설명되지 않는 경우
다음에는 docstring을 생략할 수도 있습니다:
- 아주 단순하고 명백한 함수(Very simple, obvious functions):
def add(a, b): return a + b처럼 이름과 매개변수만으로 목적이 아주 분명한 경우 - 비공개 헬퍼 함수(Private helper functions): 더 큰 함수 내부에서만 쓰이는 작은 내부 함수(다만 이런 함수도 짧은 docstring이 도움이 됩니다)
Docstring은 주석이 아닙니다
docstring은 주석과 목적이 다르다는 점을 기억하세요:
- Docstring: 함수가 무엇을 하고 어떻게 사용하는지(인터페이스)를 설명합니다
- 주석(Comments): 코드가 내부적으로 어떻게 동작하는지(구현)를 설명합니다
def calculate_grade(score, total):
"""Calculate the percentage grade from a score.
Parameters:
score (int): Points earned
total (int): Total points possible
Returns:
float: The percentage grade (0-100)
"""
# 0으로 나누는 것을 방지
if total == 0:
return 0.0
# 백분율을 계산하고 소수 둘째 자리까지 반올림
percentage = (score / total) * 100
return round(percentage, 2)docstring은 사용자에게 함수가 무엇을 하는지와 사용 방법을 알려 줍니다. 주석은 코드를 읽는 사람이 특정 구현 세부 사항을 이해하도록 돕습니다.
좋은 문서화 습관 만들기
명확한 docstring을 쓰는 습관은 큰 이득을 가져옵니다:
- 함수를 작성하면서 docstring도 함께 작성하기: 나중으로 미루지 말고, 함수의 목적이 머릿속에 선명할 때 문서화하세요
- docstring을 최신 상태로 유지하기: 함수의 동작을 바꾸면 docstring도 업데이트하세요
- 간결하지만 완전하게 작성하기: 필요한 정보는 모두 포함하되, 불필요하게 장황해지지 않도록 하세요
- 도움이 된다면 예시를 사용하기: 복잡한 함수라면 docstring 안의 사용 예시가 매우 유용할 수 있습니다
좋은 문서는 코드를 더 전문적으로 만들고, 유지보수를 더 쉽게 하며, 다른 사람(미래의 자신 포함)에게도 더 가치 있게 만들어 줍니다.