19. Definir y llamar funciones
19.1) Qué son las funciones y por qué importan
Una función(function) es un bloque de código con nombre que realiza una tarea específica. Ya has estado usando funciones a lo largo de este libro—print(), input(), len(), type(), y muchas otras. Estas son funciones integradas que proporciona Python. Ahora aprenderás a crear tus propias funciones personalizadas para organizar tu código y hacerlo reutilizable.
Por qué importan las funciones
Las funciones son fundamentales para escribir programas claros y mantenibles. Proporcionan varios beneficios críticos:
1. Reutilización de código
Sin funciones, tendrías que copiar y pegar el mismo código cada vez que quieras realizar una tarea. Considera calcular el área de un rectángulo en varios lugares:
# Sin funciones: código repetitivo
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: 60Esta repetición es tediosa y propensa a errores. Si necesitas cambiar cómo calculas el área (quizá para incluir unidades o redondeo), tendrías que actualizar cada ubicación. Las funciones resuelven este problema al permitirte escribir el código una vez y usarlo muchas veces.
2. Organización del código
Las funciones dividen los programas grandes en piezas más pequeñas y manejables. Cada función se encarga de una tarea específica, haciendo que tu código sea más fácil de entender y mantener. En lugar de un script largo con cientos de líneas, puedes organizar operaciones relacionadas en funciones con nombre que comuniquen claramente su propósito.
3. Abstracción(abstraction)
Las funciones ocultan los detalles de implementación detrás de una interfaz simple. Cuando llamas a len(my_list), no necesitas saber cómo Python cuenta los elementos—simplemente obtienes el resultado. De forma similar, tus funciones pueden proporcionar interfaces simples para operaciones complejas, haciendo que tu código sea más fácil de usar y entender.
4. Pruebas(testing) y depuración(debugging)
Las funciones facilitan probar piezas individuales de tu programa. Puedes verificar que cada función funciona correctamente de forma aislada antes de combinarlas en un programa más grande. Cuando algo sale mal, las funciones te ayudan a acotar dónde está ocurriendo el problema.
A lo largo del resto de este capítulo, aprenderás a definir tus propias funciones, pasarles información, recuperar resultados y documentarlas claramente. Estas habilidades son esenciales para escribir código Python profesional.
19.2) Definir funciones con def
Para crear una función en Python, usas la palabra clave def (abreviatura de "define"). La estructura básica de una definición de función se ve así:
def function_name():
# Bloque de código que se ejecuta cuando se llama a la función
statement1
statement2
# ... más sentenciasDesglosemos cada parte:
def: La palabra clave que le dice a Python que estás definiendo una funciónfunction_name: El nombre que eliges para tu función (sigue las mismas reglas que los nombres de variables)(): Paréntesis que eventualmente contendrán parámetros (veremos eso en la siguiente sección):: Dos puntos que marcan el final del encabezado de la función- Bloque de código indentado: Las sentencias que componen el cuerpo de la función (deben estar indentadas)
Tu primera función
Aquí tienes una función simple que imprime un saludo:
def greet():
print("Hello!")
print("Welcome to Python functions.")
# Llama a la función
greet()Output:
Hello!
Welcome to Python functions.Cuando defines una función, Python la recuerda pero no ejecuta el código dentro de ella de inmediato. El código solo se ejecuta cuando llamas a la función escribiendo su nombre seguido de paréntesis: greet().
Convenciones para nombrar funciones
Los nombres de funciones siguen las mismas reglas que los nombres de variables (como aprendimos en el Capítulo 3):
- Usa letras minúsculas
- Separa palabras con guiones bajos (snake_case)
- Empieza con una letra o guion bajo, no con un dígito
- Usa nombres descriptivos que indiquen qué hace la función
# Buenos nombres de funciones
def calculate_total():
pass
def get_user_age():
pass
def display_menu():
pass
# Malos nombres de funciones (pero sintácticamente válidos)
def x(): # No descriptivo
pass
def CalculateTotal(): # Debería usar minúsculas
pass
def calc(): # Demasiado abreviado
passNota: Usamos pass aquí como un marcador de posición (como aprendimos en el Capítulo 8). No hace nada, pero permite que la definición de la función esté completa sintácticamente.
Las funciones pueden contener cualquier código
El cuerpo de una función puede contener cualquier sentencia de Python que hayas aprendido hasta ahora: asignaciones de variables, condicionales, bucles(loop), e incluso llamadas a otras funciones.
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.Múltiples definiciones de funciones
Puedes definir tantas funciones como necesites en tu programa. Cada función es independiente y se puede llamar por separado:
def morning_greeting():
print("Good morning!")
def evening_greeting():
print("Good evening!")
# Llama a cada función
morning_greeting()
evening_greeting()Output:
Good morning!
Good evening!Orden de definición de funciones
En Python, debes definir una función antes de llamarla. El intérprete de Python lee tu código de arriba hacia abajo, así que si intentas llamar a una función antes de definirla, obtendrás un error:
# ADVERTENCIA: Esto causará un NameError - solo para demostración
# PROBLEMA: Se llama a la función antes de que esté definida
say_hello() # NameError: name 'say_hello' is not defined
def say_hello():
print("Hello!")El orden correcto es definir primero y luego llamar:
# Correcto: definir primero
def say_hello():
print("Hello!")
# Luego llamar
say_hello()Output:
Hello!Sin embargo, las funciones pueden llamar a otras funciones que se definen más adelante en el archivo, siempre que esas llamadas ocurran después de todas las definiciones:
def first_function():
print("First function")
second_function() # Esto está bien: se llama en tiempo de ejecución
def second_function():
print("Second function")
# Ambas funciones están definidas antes de llamar a la primera
first_function()Output:
First function
Second functionLas funciones crean un alcance local
Las variables creadas dentro de una función existen solo dentro de esa función. Esto se llama alcance local(local scope) (lo exploraremos en detalle en el Capítulo 21). Por ahora, entiende que lo que ocurre dentro de una función se queda dentro de la función:
def create_message():
message = "This is local"
print(message)
create_message()
# Esto causaría un error:
# print(message) # NameError: name 'message' is not definedOutput:
This is localLa variable message existe solo mientras la función se está ejecutando. Una vez que la función termina, la variable desaparece.
Funciones vacías con pass
A veces quieres definir la estructura de una función pero implementarla más tarde. Usa pass como marcador de posición:
def future_feature():
pass # TODO: Implementa esto más tarde
# La función existe y se puede llamar, pero no hace nada
future_feature() # Se ejecuta sin error, no hace nadaEsto es útil cuando bosquejas la estructura de tu programa antes de completar los detalles.
19.3) Llamar funciones y pasar argumentos
Definir una función crea una pieza de código reutilizable, pero para que las funciones sean realmente potentes, necesitas pasarles información. Esta información se pasa mediante argumentos(arguments).
Parámetros vs argumentos
Antes de continuar, aclaremos dos términos que a menudo se confunden:
- Parámetro(parameter): Un nombre de variable en la definición de la función que recibirá un valor
- Argumento(argument): El valor real que pasas a la función cuando la llamas
def greet(name): # 'name' es un parámetro
print(f"Hello, {name}!")
greet("Alice") # "Alice" es un argumentoOutput:
Hello, Alice!Piensa en los parámetros como marcadores de posición y en los argumentos como los datos reales que llenan esos marcadores.
Definir funciones con parámetros
Para definir una función que acepte entrada, añade nombres de parámetros dentro de los paréntesis:
def greet_person(name):
print(f"Hello, {name}!")
print("Nice to meet you.")
# Llama con distintos argumentos
greet_person("Alice")
print() # Línea en blanco para legibilidad
greet_person("Bob")Output:
Hello, Alice!
Nice to meet you.
Hello, Bob!
Nice to meet you.El parámetro name actúa como una variable dentro de la función. Cada vez que llamas a la función, name toma el valor del argumento que proporciones.
Múltiples parámetros
Las funciones pueden aceptar múltiples parámetros, separados por comas:
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.Al llamar a una función con múltiples parámetros, el orden importa. El primer argumento va al primer parámetro, el segundo argumento al segundo parámetro, y así sucesivamente. Estos se llaman argumentos posicionales(positional arguments).
Argumentos posicionales
Con argumentos posicionales, Python empareja argumentos con parámetros según su posición:
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.Si mezclas el orden, obtendrás resultados inesperados:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# Argumentos en el orden incorrecto
describe_pet("Buddy", "dog")Output:
I have a Buddy.
My Buddy's name is dog.Esto es Python técnicamente válido, pero produce una salida sin sentido porque los argumentos están en posiciones incorrectas.
Argumentos con nombre
Para evitar errores relacionados con la posición, puedes usar argumentos con nombre(keyword arguments) nombrando explícitamente los parámetros cuando llamas a la función:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# Usar argumentos con nombre: el orden no importa
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.Con argumentos con nombre, el orden no importa porque Python empareja argumentos con parámetros por nombre, no por posición.
Mezclar argumentos posicionales y con nombre
Puedes mezclar argumentos posicionales y con nombre en una sola llamada a función, pero los argumentos posicionales deben ir primero:
def create_profile(username, email, age):
print(f"Username: {username}")
print(f"Email: {email}")
print(f"Age: {age}")
# Mezclar argumentos posicionales y con nombre
create_profile("alice123", email="alice@example.com", age=25)Output:
Username: alice123
Email: alice@example.com
Age: 25Sin embargo, no puedes poner argumentos posicionales después de argumentos con nombre:
# 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 argumentLa cantidad de argumentos debe coincidir
Cuando llamas a una función, debes proporcionar la cantidad correcta de argumentos (a menos que la función tenga valores por defecto, que veremos en el Capítulo 20):
def add_numbers(a, b):
result = a + b
print(f"{a} + {b} = {result}")
add_numbers(5, 3) # Correcto: 2 argumentos para 2 parámetrosOutput:
5 + 3 = 8Proporcionar muy pocos o demasiados argumentos causa un error:
# ADVERTENCIA: Estos causarán TypeErrors - solo para demostración
# PROBLEMA: Muy pocos argumentos
# add_numbers(5)
# TypeError: add_numbers() missing 1 required positional argument: 'b'
# PROBLEMA: Demasiados argumentos
# add_numbers(5, 3, 2)
# TypeError: add_numbers() takes 2 positional arguments but 3 were givenUsar expresiones como argumentos
Los argumentos no tienen que ser valores simples: puedes usar cualquier expresión:
def display_total(price, quantity):
total = price * quantity
print(f"Total cost: ${total:.2f}")
# Usar expresiones como argumentos
base_price = 10
display_total(base_price * 1.1, 5) # Precio con 10% de recargo
display_total(15 + 5, 3 * 2) # Ambos argumentos son expresionesOutput:
Total cost: $55.00
Total cost: $120.00Python evalúa cada expresión primero y luego pasa los valores resultantes a la función.
Llamar funciones desde dentro de funciones
Las funciones pueden llamar a otras funciones, creando una jerarquía de operaciones. Esta es una técnica potente que te permite dividir tareas complejas en piezas más pequeñas y manejables.
Aquí tienes un ejemplo con el cálculo del área de una habitación:
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 feetNota: Aquí estamos usando return, que exploraremos en detalle en la siguiente sección. Por ahora, entiende que calculate_area() envía su resultado de vuelta a la función que llama.
Aquí tienes otro ejemplo que muestra cómo las funciones pueden construirse unas sobre otras: un sistema de conversión de temperatura:
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}")
# Usa el sistema completo de conversión
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°FEn este ejemplo, display_temperature_conversion() llama a celsius_to_fahrenheit() para hacer la conversión y luego llama a format_temperature() para dar formato al resultado. Cada función tiene una única responsabilidad clara, haciendo que el código sea fácil de entender y mantener.
19.4) Usar return para devolver resultados
Hasta ahora, nuestras funciones han realizado acciones (como imprimir), pero no han enviado valores de vuelta al código que las llamó. La sentencia return permite que una función calcule un resultado y lo envíe de vuelta al llamador.
Sentencia return básica
Aquí tienes una función simple que calcula y devuelve un valor:
def add_numbers(a, b):
result = a + b
return result
# Captura el valor devuelto
sum_value = add_numbers(5, 3)
print(f"The sum is: {sum_value}")Output:
The sum is: 8Cuando Python encuentra una sentencia return, ocurren dos cosas:
- La función deja de ejecutarse inmediatamente (se ignora cualquier código después de
return) - El valor especificado se envía de vuelta al llamador
Devolver valores directamente
No necesitas guardar el resultado en una variable antes de devolverlo. Puedes devolver una expresión directamente:
def multiply(a, b):
return a * b
result = multiply(4, 7)
print(f"4 × 7 = {result}")Output:
4 × 7 = 28Esto es más conciso y es el estilo preferido para cálculos simples.
Usar valores devueltos
Una vez que una función devuelve un valor, puedes usar ese valor en cualquier lugar donde usarías cualquier otro valor:
def calculate_discount(price, discount_percent):
discount_amount = price * (discount_percent / 100)
return discount_amount
original_price = 100
discount = calculate_discount(original_price, 20)
# Usa el valor devuelto en cálculos
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 sale de la función inmediatamente
Cuando Python ejecuta una sentencia return, la función se detiene de inmediato. Cualquier código después del return nunca se ejecuta:
def check_age(age):
if age < 18:
return "Minor"
# Esta línea solo se ejecuta si age >= 18
return "Adult"
print(check_age(15))
print(check_age(25))Output:
Minor
AdultEste comportamiento es útil para manejar diferentes casos en una función. Una vez que has determinado el resultado, puedes devolverlo inmediatamente sin necesidad de comprobar condiciones adicionales.
Aquí tienes un ejemplo que demuestra cómo return detiene la ejecución:
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
PositiveFunciones sin return
Si una función no tiene una sentencia return, o si tiene un return sin valor, la función devuelve None:
def greet(name):
print(f"Hello, {name}!")
# Sin sentencia return
result = greet("Alice")
print(f"The function returned: {result}")Output:
Hello, Alice!
The function returned: NoneDe manera similar, un return vacío (sin valor) también devuelve None:
def process_data(data):
if not data:
return # Salida temprana, devuelve 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: SuccessDevolver múltiples valores
Las funciones de Python pueden devolver múltiples valores separándolos con comas. Python los empaqueta automáticamente en una tupla (como aprendimos en el Capítulo 15):
def calculate_rectangle(length, width):
area = length * width
perimeter = 2 * (length + width)
return area, perimeter
# Desempaqueta la tupla devuelta
rect_area, rect_perimeter = calculate_rectangle(5, 3)
print(f"Area: {rect_area}")
print(f"Perimeter: {rect_perimeter}")Output:
Area: 15
Perimeter: 16También puedes capturar la tupla como un solo valor:
def get_student_info():
name = "Alice"
age = 20
grade = "A"
return name, age, grade
# Captura como una tupla
student = get_student_info()
print(f"Student info: {student}")
print(f"Name: {student[0]}")Output:
Student info: ('Alice', 20, 'A')
Name: AliceDevolver distintos tipos
Una función puede devolver tipos diferentes de valores dependiendo de la situación:
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 zeroAunque esto funciona, por lo general es una mejor práctica manejar los errores de otra manera (aprenderemos sobre excepciones en la Parte VII). Por ahora, entiende que las funciones pueden devolver diferentes tipos, aunque a menudo es más claro ser consistente.
19.5) Documentar funciones con docstrings
A medida que tus programas crecen y creas más funciones, se vuelve crucial documentar qué hace cada función. Python proporciona una forma integrada de documentar funciones usando docstrings (cadenas de documentación).
¿Qué es un docstring?
Un docstring es un literal de cadena que aparece como la primera sentencia en una función (o módulo, clase o método). Describe qué hace la función, qué parámetros acepta y qué devuelve. Los docstrings se encierran entre comillas triples (""" o '''), lo que les permite abarcar múltiples líneas.
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 * widthPor qué importan los docstrings
Los docstrings cumplen varios propósitos importantes:
- Autodocumentación: Explican qué hace tu función sin requerir que los lectores analicen el código
- Soporte del IDE: Muchas herramientas de desarrollo muestran los docstrings como tooltips cuando usas una función
- Función help(): La función integrada
help()de Python muestra docstrings - Práctica profesional: Un código bien documentado es más fácil de mantener y compartir con otros
Formato básico de docstring
Para funciones simples, un docstring de una línea es suficiente:
def greet(name):
"""Print a personalized greeting."""
print(f"Hello, {name}!")
# Accede al docstring
print(greet.__doc__)Output:
Print a personalized greeting.El docstring debería ser una descripción concisa de lo que hace la función, escrita como un mandato ("Calculate...", "Return...", "Print...") en lugar de una descripción ("This function calculates...").
Docstrings de varias líneas
Para funciones más complejas, usa docstrings de varias líneas que incluyan:
- Un resumen breve en la primera línea
- Una línea en blanco
- Una descripción más detallada
- Información sobre parámetros
- Información sobre valores de retorno
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)
# Usa help() para ver el docstring completo
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 priceConvenciones de docstring
Python tiene convenciones establecidas para escribir docstrings (documentadas en PEP 257). Aquí están las pautas clave:
1. Usa comillas dobles triples: """docstring"""
def good_example():
"""This follows the convention."""
pass
def also_valid():
'''This works but is less common.'''
pass2. Los docstrings de una línea deberían caber en una línea:
def add(a, b):
"""Return the sum of a and b."""
return a + b3. Los docstrings de varias líneas deberían tener una línea de resumen y luego una línea en blanco:
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'
"""
# Implementación de la función aquí
passDescribir parámetros y valores de retorno
Al documentar parámetros y valores de retorno, sé específico sobre:
- Nombres de parámetros: Que coincidan con los nombres reales de los parámetros en la función
- Tipos: Qué tipo de dato se espera (aprenderemos sobre type hints en el Capítulo 43)
- Propósito: Para qué se usa el parámetro
- Valor de retorno: Qué devuelve la función y bajo qué condiciones
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 NoneDocstrings para funciones con múltiples tipos de retorno
Cuando una función puede devolver distintos tipos dependiendo de la situación, documenta todas las posibilidades:
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 / bAcceder a docstrings
Puedes acceder al docstring de una función de tres maneras:
1. Usando el atributo __doc__:
def example():
"""This is an example function."""
pass
print(example.__doc__)Output:
This is an example function.2. Usando la función 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. En entornos de desarrollo interactivos: La mayoría de los IDEs y editores de código muestran docstrings como tooltips cuando pasas el cursor sobre, o escribes, el nombre de una función.
Cuándo escribir docstrings
Deberías escribir docstrings para:
- Todas las funciones públicas: Funciones que están pensadas para ser usadas por otras partes de tu programa o por otros programadores
- Funciones complejas: Cualquier función cuyo propósito o comportamiento no sea inmediatamente obvio por su nombre y parámetros
- Funciones con parámetros no obvios: Cuando los nombres de los parámetros por sí solos no explican completamente qué valores se esperan
Podrías omitir docstrings para:
- Funciones muy simples y obvias: Funciones como
def add(a, b): return a + bdonde el nombre y los parámetros dejan el propósito totalmente claro - Funciones auxiliares privadas: Funciones internas pequeñas usadas solo dentro de una función mayor (aunque incluso estas se benefician de docstrings breves)
Los docstrings no son comentarios
Recuerda que los docstrings cumplen un propósito diferente al de los comentarios:
- Docstrings: Describen qué hace una función y cómo usarla (la interfaz)
- Comentarios: Explican cómo funciona el código internamente (la implementación)
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)
"""
# Evitar división por cero
if total == 0:
return 0.0
# Calcular el porcentaje y redondear a 2 decimales
percentage = (score / total) * 100
return round(percentage, 2)El docstring le dice a los usuarios qué hace la función y cómo usarla. Los comentarios explican detalles específicos de la implementación a alguien que esté leyendo el código.
Construir buenos hábitos de documentación
Escribir docstrings claros es un hábito que rinde frutos:
- Escribe docstrings mientras escribes funciones: No esperes hasta después—documenta mientras el propósito de la función está fresco en tu mente
- Mantén los docstrings actualizados: Cuando cambies el comportamiento de una función, actualiza su docstring
- Sé conciso pero completo: Incluye toda la información necesaria, pero evita la verbosidad innecesaria
- Usa ejemplos cuando sea útil: Para funciones complejas, un ejemplo de uso en el docstring puede ser invaluable
Una buena documentación hace que tu código sea más profesional, más fácil de mantener y más valioso para otros (incluyéndote a ti en el futuro).