19. Определение и вызов функций
19.1) Что такое функции и почему они важны
Функция(function) — это именованный блок кода, который выполняет конкретную задачу. Вы уже использовали функции на протяжении всей этой книги — print(), input(), len(), type() и многие другие. Это встроенные функции(built-in functions), которые предоставляет Python. Теперь вы научитесь создавать собственные пользовательские функции(custom functions), чтобы организовывать код и делать его переиспользуемым.
Почему функции важны
Функции — основа написания понятных, сопровождаемых программ. Они дают несколько критически важных преимуществ:
1. Переиспользование кода
Без функций вам пришлось бы копировать и вставлять один и тот же код каждый раз, когда вы хотите выполнить задачу. Рассмотрим вычисление площади прямоугольника в нескольких местах:
# Без функций — повторяющийся код
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. Организация кода
Функции разбивают большие программы на небольшие, управляемые части. Каждая функция обрабатывает одну конкретную задачу, что делает код проще для понимания и сопровождения. Вместо одного длинного скрипта на сотни строк вы можете организовать связанные операции в именованные функции, которые ясно сообщают о своём назначении.
3. Абстракция(abstraction)
Функции скрывают детали реализации за простым интерфейсом. Когда вы вызываете len(my_list), вам не нужно знать, как Python считает элементы — вы просто получаете результат. Аналогично, ваши функции могут предоставлять простые интерфейсы к сложным операциям, делая код проще в использовании и понимании.
4. Тестирование и отладка(debugging)
Функции упрощают тестирование отдельных частей вашей программы. Вы можете проверить, что каждая функция работает правильно изолированно, прежде чем объединять их в более крупную программу. Когда что-то идёт не так, функции помогают сузить круг поиска места, где возникает проблема.
В оставшейся части этой главы вы научитесь определять собственные функции, передавать им информацию, получать результаты обратно и ясно их документировать. Эти навыки необходимы для написания профессионального кода Python.
19.2) Определение функций с помощью def
Чтобы создать функцию в Python, используется ключевое слово def (сокращение от "define"). Базовая структура определения функции выглядит так:
def function_name():
# Блок кода, который выполняется при вызове функции
statement1
statement2
# ... больше операторовРазберём каждую часть:
def: ключевое слово, которое говорит Python, что вы определяете функциюfunction_name: имя, которое вы выбираете для своей функции (подчиняется тем же правилам, что и имена переменных)(): круглые скобки, которые со временем будут содержать параметры (мы рассмотрим их в следующем разделе):: двоеточие, которое отмечает конец заголовка функции- Блок кода с отступом: операторы, составляющие тело функции (должны быть с отступом)
Ваша первая функция
Вот простая функция, которая печатает приветствие:
def greet():
print("Hello!")
print("Welcome to Python functions.")
# Вызов функции
greet()Output:
Hello!
Welcome to Python functions.Когда вы определяете функцию, Python запоминает её, но не выполняет код внутри сразу. Код выполняется только тогда, когда вы вызываете(call) функцию, написав её имя, за которым следуют круглые скобки: greet().
Соглашения об именовании функций
Имена функций подчиняются тем же правилам, что и имена переменных (как мы изучали в Главе 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, которые вы уже изучили: присваивания переменных, условия(conditionals), циклы(loops) и даже вызовы других функций.
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!")
# Вызов каждой функции
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()
# Это вызвало бы ошибку:
# print(message) # NameError: name 'message' is not definedOutput:
This is localПеременная message существует только пока выполняется функция. Как только функция завершится, переменная исчезает.
Пустые функции с pass
Иногда вы хотите определить структуру функции, но реализовать её позже. Используйте pass как заглушку:
def future_feature():
pass # TODO: Реализовать это позже
# Функция существует и может быть вызвана, но ничего не делает
future_feature() # Выполняется без ошибки, ничего не делаетЭто полезно, когда вы набрасываете структуру программы, прежде чем заполнять детали.
19.3) Вызов функций и передача аргументов
Определение функции создаёт переиспользуемый фрагмент кода, но чтобы сделать функции по-настоящему мощными, нужно передавать им информацию. Эта информация передаётся через аргументы(arguments).
Параметры и аргументы
Прежде чем продолжить, проясним два термина, которые часто путают:
- Параметр(parameter): имя переменной в определении функции, которое будет получать значение
- Аргумент(argument): фактическое значение, которое вы передаёте функции при вызове
def greet(name): # 'name' — параметр
print(f"Hello, {name}!")
greet("Alice") # "Alice" — аргументOutput:
Hello, Alice!Думайте о параметрах как о заполнителях, а об аргументах — как о фактических данных, которые заполняют эти заполнители.
Определение функций с параметрами
Чтобы определить функцию, которая принимает ввод, добавьте имена параметров внутри круглых скобок:
def greet_person(name):
print(f"Hello, {name}!")
print("Nice to meet you.")
# Вызов с разными аргументами
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}.")
# Аргументы в неправильном порядке
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}.")
# Использование именованных аргументов — порядок не важен
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}")
# Смешивание позиционных и именованных аргументов
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}")
# Использование выражений в качестве аргументов
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}")
# Используйте полную систему преобразования
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
# Сохранить возвращённое значение
sum_value = add_numbers(5, 3)
print(f"The sum is: {sum_value}")Output:
The sum is: 8Когда Python встречает оператор 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)
# Использовать возвращённое значение в вычислениях
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"
# Эта строка выполняется только если age >= 18
return "Adult"
print(check_age(15))
print(check_age(25))Output:
Minor
AdultТакое поведение полезно для обработки разных случаев в функции. Как только вы определили результат, вы можете сразу вернуть его, не проверяя дополнительные условия.
Вот пример, который демонстрирует, как 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
PositiveФункции без return
Если в функции нет оператора 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
# Распаковать возвращённый кортеж
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
# Захватить как кортеж
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Хотя это работает, в целом лучше обрабатывать ошибки по-другому (мы узнаем об исключениях в Части VII). Пока что поймите, что функции могут возвращать разные типы, хотя часто понятнее сохранять согласованность.
19.5) Документирование функций с помощью docstrings
По мере роста ваших программ и создания большего числа функций становится критически важно документировать, что делает каждая функция. Python предоставляет встроенный способ документирования функций с помощью docstring(docstrings) (строк документации).
Что такое 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 * widthПочему docstrings важны
Docstrings служат нескольким важным целям:
- Самодокументирование: они объясняют, что делает ваша функция, не требуя от читателя анализировать код
- Поддержка IDE: многие инструменты разработки показывают docstring как подсказки, когда вы используете функцию
- Функция help(): встроенная функция Python
help()отображает docstring - Профессиональная практика: хорошо документированный код проще сопровождать и делиться им с другими
Базовый формат docstring
Для простых функций достаточно однострочного docstring:
def greet(name):
"""Print a personalized greeting."""
print(f"Hello, {name}!")
# Доступ к docstring
print(greet.__doc__)Output:
Print a personalized greeting.Docstring должен быть кратким описанием того, что делает функция, написанным как команда («Calculate...», «Return...», «Print...»), а не как описание («This function calculates...»).
Многострочные 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)
# Используйте help() чтобы увидеть полный 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 priceСоглашения для docstring
В 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Описание параметров и возвращаемых значений
При документировании параметров и возвращаемых значений будьте конкретны относительно:
- Имена параметров: должны совпадать с фактическими именами параметров в функции
- Типы: какой тип данных ожидается (мы узнаем о подсказках типов(type hints) в Главе 43)
- Назначение: для чего используется параметр
- Возвращаемое значение: что возвращает функция и при каких условиях
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 NoneDocstring для функций с несколькими типами возвращаемых значений
Когда функция может возвращать разные типы в зависимости от ситуации, документируйте все варианты:
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 / bДоступ к docstring
Вы можете получить доступ к 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 для:
- Всех публичных функций: функций, предназначенных для использования другими частями вашей программы или другими программистами
- Сложных функций: любой функции, чьё назначение или поведение не очевидны сразу из её имени и параметров
- Функций с неочевидными параметрами: когда имена параметров сами по себе не полностью объясняют, какие значения ожидаются
Вы можете пропустить docstring для:
- Очень простых, очевидных функций: функций вроде
def add(a, b): return a + b, где имя и параметры делают назначение кристально ясным - Приватных вспомогательных функций: небольших внутренних функций, используемых только внутри более крупной функции (хотя даже для них полезны краткие docstring)
Docstring — это не комментарии
Помните, что docstring служат другой цели, чем комментарии:
- Docstring: описывают, что делает функция и как ею пользоваться (интерфейс)
- Комментарии: объясняют, как код работает внутри (реализация)
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)
"""
# Избегаем деления на ноль
if total == 0:
return 0.0
# Вычисляем процент и округляем до 2 знаков после запятой
percentage = (score / total) * 100
return round(percentage, 2)Docstring сообщает пользователям, что делает функция и как ею пользоваться. Комментарии объясняют конкретные детали реализации тому, кто читает код.
Формирование хороших привычек документирования
Написание понятных docstring — это привычка, которая окупается:
- Пишите docstring вместе с написанием функций: не откладывайте на потом — документируйте, пока назначение функции свежо в памяти
- Держите docstring актуальными: когда вы меняете поведение функции, обновляйте её docstring
- Будьте краткими, но полными: включайте всю необходимую информацию, но избегайте ненужной многословности
- Используйте примеры, когда это полезно: для сложных функций пример использования в docstring может быть бесценным
Хорошая документация делает ваш код более профессиональным, проще в сопровождении и более ценным для других (включая вас в будущем).