Funciones
A medida que tus programas crecen, vas a terminar escribiendo la misma lógica en más de un lugar. Las funciones te permiten escribir esa lógica una sola vez, ponerle nombre y usarla en todas partes. Si la corriges en un solo lugar, cada llamada recibe la corrección automáticamente.
def greet(name):
return f"Hello, {name}!"
print(greet("Alicia")) # "Hello, Alicia!"
print(greet("Roberto")) # "Hello, Roberto!"Escríbela una vez, úsala en todas partes, corrígela en un solo lugar.
Definir una función
La palabra clave def inicia la definición de una función, seguida por el nombre, paréntesis, dos puntos y un cuerpo indentado. Una función no hace nada hasta que la llamas. Defínela con def y luego llámala por su nombre con ().
def say_hello():
print("Hello!")
say_hello() # llama a la funcióndef nombre(): e indenta el cuerpo debajo. No pasa nada hasta que la llamas con nombre(), el def solo la prepara. Y si te olvidas del return, la función devuelve None silenciosamente, algo que me hizo tropezar más de una vez al principio. Parámetros y argumentos
Los parámetros son las entradas que espera tu función. Los listas dentro de los paréntesis. Cuando llamas a la función, los valores que pasas se emparejan con los parámetros en orden.
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("Alicia", "Hello") # "Hello, Alicia!"
greet("Roberto", "Hi") # "Hi, Roberto!"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 dos palabras indistintamente; la distinción importa principalmente cuando lees documentación.
Valores por defecto
Puedes darle a un parámetro un valor por defecto. Si quien llama no proporciona ese argumento, se usa el valor por defecto. Los parámetros con valores por defecto deben venir después de los parámetros sin valores por defecto.
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Alicia") # "Hello, Alicia!"
greet("Alicia", "Hi") # "Hi, Alicia!"Los parámetros con valores por defecto deben venir después de los parámetros sin valores por defecto.
Argumentos con nombre
Al llamar a una función, puedes nombrar los argumentos. Esto hace que las llamadas sean más legibles, especialmente en 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("Alicia", 87, 5) # posicional
describe_player(name="Alicia", level=5, score=87) # con nombre, en cualquier orden
describe_player("Alicia", level=5, score=87) # mezcla: posicionales primeroscore=87) y la llamada se explica sola, además puedes pasarlos en cualquier orden. La única regla: los argumentos posicionales van antes que los nombrados. Ideal para funciones con un montón de parámetros. Valores de retorno
return envía un valor de vuelta a quien llamó la función. Sin return, una función devuelve None. Una vez que se ejecuta return, la función termina de inmediato. Cualquier código que venga después en ese bloque se omite.
def add(a, b):
return a + b
result = add(3, 4) # result = 7
print(result)return también sale de la función de inmediato. Cualquier código que venga después en ese bloque no se ejecuta.
return entrega un valor a quien llamó la función, y la función se detiene ahí mismo, cualquier cosa después se omite. Si omites el return, obtienes None de vuelta. print muestra un valor, return lo entrega para poder usarlo, me tomó un rato sentir esa diferencia. Retornar varios valores
Python te permite retornar varios valores separándolos con comas. Quien llama los recibe como una tupla y puede desempaquetarlos en nombres separados en una sola 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 desempaquetado: Python asigna cada valor retornado al nombre correspondiente.
low, high = min_max(...), un nombre por cada valor. Útil siempre que una función produzca naturalmente más de una respuesta. Alcance (scope)
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. Casi nunca necesitas eso: pasa valores como entrada, devuelve resultados, y la función se mantiene fácil 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 la variable global
count += 1
increment()
print(count) # 1Usar global debería ser el último recurso. Hace que el código sea más difícil de razonar. Prefiere pasar valores como entrada y devolverlos como salida. El alcance se apoya directamente en cómo la asignación vincula un nombre a un valor, tema que se cubre en el capítulo Variables y tipos.
*args y **kwargs
A veces no sabes cuántos argumentos va a recibir una función. *args recolecta cualquier cantidad de argumentos posicionales en una tupla. **kwargs recolecta cualquier cantidad de argumentos con nombre en un diccionario. Los nombres args y kwargs son convenciones; los asteriscos son lo que realmente 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="Alicia", score=87, level=5)Puedes combinarlos con parámetros normales. Los parámetros normales van primero:
def describe(title, *tags, **metadata):
print(f"{title} | tags: {tags} | meta: {metadata}")
describe("Introducción a Python", "beginner", "python", author="Alicia", year=2024)*args junta cualquier cantidad de argumentos posicionales extra en una tupla, **kwargs junta los extra con nombre en un dict. Las palabras args y kwargs son solo convención, el * y el ** hacen el trabajo real. Útil cuando no puedes saber de antemano cuántas cosas van a llegar. Docstrings
Un docstring es una cadena de texto al comienzo 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 a la función. Usa comillas triples, y escribe una sola línea para funciones simples.
def normalise(value, min_val, max_val):
"""Scale a value to the 0-1 range given the known min and max."""
return (value - min_val) / (max_val - min_val)def build_url(base, version, resource, *, secure=True):
"""
Build an API endpoint URL.
Returns a fully-qualified URL string. If secure is False,
the URL will use http instead of 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 evidente a partir de su nombre y su firma.
Type hints
Los type hints te permiten anotar qué tipos espera y devuelve una función. Python no los hace cumplir en tiempo de ejecución, pero los editores los usan para detectar errores antes de que ejecutes 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]Los type hints son opcionales pero valiosos en cualquier función que se llame desde varios lugares. Son documentación que las herramientas pueden verificar.
name: str y -> str para el retorno. Python no los va a hacer cumplir cuando corre, pero tu editor los lee y te avisa antes de que ejecutes. Piensa en ellos como notas que las herramientas pueden revisar. Funciones como valores
Las funciones en Python son valores, como las cadenas o los números. Puedes asignarlas a variables y pasarlas a otras funciones. Así es como 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 aparece constantemente con sorted(), map() y filter(). También lo vas a ver en el capítulo Lambdas y comprehensions.
key= a sorted(). Me pareció raro al principio, luego hizo clic y empezó a aparecer en todas partes. En la práctica
Dos funciones que trabajan juntas: letter_grade convierte una nota en una letra, y summarise la llama para cada nota 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])
