Funciones

A medida que tus programas crecen, escribirás la misma lógica en más de un lugar. Las funciones te permiten escribir la lógica una vez, nombrarla, y usarla en todas partes. Corrígela en un lugar y cada llamada obtiene la corrección automáticamente.
def greet(name):
return f"Hello, {name}!"
print(greet("María")) # "Hello, María!"
print(greet("Carlos")) # "Hello, Carlos!"Escríbela una vez, úsala en todas partes, corrígela en un lugar.
Definir una función
La palabra clave def inicia una definición de función, seguida del nombre, paréntesis, dos puntos, y un cuerpo indentado. Una función no hace nada hasta que la llames. Defínela con def, luego llámala por nombre con ().
def say_hello():
print("Hello!")
say_hello() # llama la funcióndef name(): e indenta el cuerpo debajo. Nada ocurre hasta que la llames con name(), el def solo la configura. Y si olvidas un return, la función silenciosamente devuelve None, eso me atrapó más de una vez al principio. Parámetros y argumentos
Los parámetros son las entradas que tu función espera. Lístalos dentro de los paréntesis. Cuando llamas la función, los valores que pasas se emparejan a los parámetros en orden.
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("María", "Hola") # "Hola, María!"
greet("Carlos", "Saludos") # "Saludos, Carlos!"Parámetro es el nombre en la definición de la función. Argumento es el valor real que pasas cuando la llamas. En la práctica la gente usa las palabras indistintamente; la distinción importa principalmente cuando lees documentos.
Valores predeterminados
Puedes darle a los parámetros un valor predeterminado. Si el llamador no proporciona ese argumento, se usa el predeterminado. Los parámetros con valores predeterminados deben venir después de los parámetros sin valores predeterminados.
def greet(name, greeting="Hola"):
print(f"{greeting}, {name}!")
greet("María") # "Hola, María!"
greet("María", "Saludos") # "Saludos, María!"Los parámetros con valores predeterminados deben venir después de los parámetros sin valores predeterminados.
Argumentos nombrados
Al llamar una función, puedes nombrar los argumentos. Esto hace las llamadas legibles, especialmente para funciones con muchos parámetros, y te permite pasarlos en cualquier orden.
def describe_player(name, score, level):
print(f"{name} | Score: {score} | Level: {level}")
describe_player("María", 87, 5) # posicional
describe_player(name="María", level=5, score=87) # nombrado, cualquier orden
describe_player("María", level=5, score=87) # mezcla: posicional primeroscore=87) y la llamada se explica a sí misma, además puedes pasarlos en cualquier orden. La única regla: cualquier argumento posicional viene antes de los nombrados. Excelente para funciones con un montón de parámetros. Valores de retorno
return envía un valor de vuelta al llamador. Sin return, una función devuelve None. Una vez que return se ejecuta, la función sale inmediatamente. Cualquier código después de él en ese bloque es saltado.
def add(a, b):
return a + b
result = add(3, 4) # result = 7
print(result)return también sale de la función inmediatamente. Cualquier código después de él en ese bloque no se ejecuta.
return entrega un valor de vuelta a quien llamó la función, y la función se detiene justo allí, cualquier cosa después de él es saltada. Omite return y obtienes None de vuelta. print muestra un valor, return lo devuelve para usar, me tomó un tiempo sentir esa diferencia. Devolver múltiples valores
Python te permite devolver múltiples valores separándolos con comas. El llamador los recibe como una tupla y puede desempaquetarlos en nombres separados en una línea.
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 7, 1, 9, 4])
print(low, high) # 1 9La sintaxis low, high = ... es desempaquetamiento: Python asigna cada valor devuelto al nombre correspondiente.
low, high = min_max(...), un nombre por valor. Práctico siempre que una función naturalmente produce más de una respuesta. Alcance
Las variables creadas dentro de una función existen solo dentro de esa función. No puedes verlas desde afuera. Las variables definidas fuera de todas las funciones son visibles en todas partes, pero no puedes cambiarlas desde dentro de una función sin una declaración explícita.
global primero. Recurre a eso casi nunca: pasa valores adentro, devuelve resultados afuera, y la función permanece simple de seguir. def calculate():
result = 42 # local a esta función
return result
calculate()
print(result) # NameError, result no existe aquí afueracount = 0
def increment():
global count # declara que quieres modificar el global
count += 1
increment()
print(count) # 1Usar global debe ser un último recurso. Hace el código más difícil de razonar. Prefiere pasar valores adentro y devolverlos afuera. El alcance se construye directamente sobre cómo la asignación vincula un nombre a un valor, cubierto en el capítulo Variables y tipos.
*args y **kwargs
A veces no sabes cuántos argumentos recibirá una función. *args recoge cualquier número de argumentos posicionales en una tupla. **kwargs recoge cualquier número de argumentos nombrados en un diccionario. Los nombres args y kwargs son convenciones; los asteriscos son lo que importa.
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="María", score=87, level=5)Puedes mezclarlos con parámetros regulares. Los parámetros regulares vienen primero:
def describe(title, *tags, **metadata):
print(f"{title} | tags: {tags} | meta: {metadata}")
describe("Intro a Python", "principiante", "python", author="María", year=2024)*args recoge cualquier número de argumentos posicionales extra como una tupla, **kwargs recoge los nombrados extra como un dict. Las palabras args y kwargs son solo convención, los * y ** hacen el trabajo real. Práctico cuando no puedes decir de antemano cuántas cosas llegan. Docstrings
Un docstring es una cadena en la parte superior de una función que describe qué hace. Los editores y herramientas de Python la usan para mostrar ayuda cuando pasas el cursor sobre una llamada de función. Usa comillas triples, y escribe una línea para funciones simples.
def normalise(value, min_val, max_val):
"""Escala un valor al rango 0-1 dados el mín y máx conocidos."""
return (value - min_val) / (max_val - min_val)def build_url(base, version, resource, *, secure=True):
"""
Construye una URL de endpoint de API.
Devuelve una cadena de URL completamente calificada. Si secure es False,
la URL usará http en lugar de https.
"""
scheme = "https" if secure else "http"
base = base.replace("https://", "").replace("http://", "")
return f"{scheme}://{base}/{version}/{resource}"Escribe un docstring para cualquier función cuyo propósito no sea claro desde su nombre y firma.
Anotaciones de tipo
Las anotaciones de tipo te permiten anotar qué tipos espera una función y retorna. Python no las impone en tiempo de ejecución, pero los editores las usan para atrapar errores antes de ejecutar nada. El -> antes de los dos puntos especifica el tipo de retorno.
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]Las anotaciones de tipo son opcionales pero valiosas en cualquier función que sea llamada desde múltiples lugares. Son documentación que las herramientas pueden verificar.
name: str y -> str para el retorno. Python no las impondrá cuando se ejecute, pero tu editor las lee y te advierte antes de presionar ejecutar. Piénsalas como notas que las herramientas pueden verificar. Funciones como valores
Las funciones en Python son valores, como cadenas o números. Puedes asignarlas a variables y pasarlas a otras funciones. Esto es cómo sorted() acepta una función key=.
def double(x):
return x * 2
def apply(func, value):
return func(value)
apply(double, 5) # 10Pasar funciones como argumentos se muestra constantemente con sorted(), map(), y filter(). También lo verás en el capítulo Lambdas y comprehensions.
key= a sorted(). Se sintió extraño para mí al principio, luego hizo clic y apareció en todas partes. En la práctica
Dos funciones que trabajan juntas: letter_grade convierte una puntuación a una letra, y summarise la llama para cada puntuación en una lista:
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 = []
for s in scores:
grades.append(letter_grade(s))
print(f"Average: {avg:.1f}")
print(f"Grades: {', '.join(grades)}")
summarise([87, 92, 74, 65, 91])
