Parámetros y Argumentos
Un procedimiento que siempre hace lo mismo es poco más que una macro con pretensiones. Un robot que solo corta madera de exactamente 1 metro no sirve de nada en un almacén donde los pedidos varían. Lo que hace útil a una función es que acepta variables. Eso es lo que controlan los parámetros y los argumentos.
Parámetros: Los Requisitos (El Formulario)
Piensa en el SOP como un formulario impreso: tiene huecos en blanco con etiquetas. Cuando defines la función, esos huecos son los Parámetros. No son datos todavía, son promesas de que llegará un dato.
# 'producto' y 'cantidad' son los huecos a llenar
def generar_pedido(producto: str, cantidad: int) -> None:
print(f"Pedido recibido: {cantidad} cajas de {producto}")
Argumentos: Los Datos Reales (El Contenido)
El formulario impreso no hace nada solo. Alguien tiene que llenarlo con información concreta antes de mandarlo. Cuando ejecutas la función y le pasas valores reales, esos valores son los Argumentos.
# "Tornillos" y 500 son los datos reales
generar_pedido("Tornillos", 500)
La distinción es más útil de lo que parece. Parámetro es vocabulario de la definición; argumento es vocabulario del uso. Confundirlos genera conversaciones raras cuando describes errores.

Fig. 9.4: El parámetro recibe al argumento.
Formas de Llenar el Formulario
Tienes dos maneras de pasar los datos:
-
Por Posición (Confianza): Asumes que el primero va al primero y el segundo al segundo.
generar_pedido("Tornillos", 500) -
Por Nombre (Explícito): Etiquetas cada dato. Es más seguro y claro. El orden no importa.
generar_pedido(cantidad=500, producto="Tornillos")
Nota: Si tu función tiene más de dos parámetros, usa siempre argumentos por nombre: te evitarás confusiones.
Valores por Defecto (Huecos ya Rellenados)
Algunos huecos del formulario casi siempre llevan el mismo valor. En vez de obligar a escribirlo cada vez, le das un valor por defecto en la definición: si quien llama no lo pasa, se usa ese. Si lo pasa, manda el suyo.
def generar_pedido(producto: str, cantidad: int = 1) -> None:
print(f"Pedido: {cantidad} cajas de {producto}")
generar_pedido("Tornillos") # cantidad usa el defecto: 1
generar_pedido("Tornillos", 500) # cantidad llega como 500
Una regla del lenguaje: los parámetros con valor por defecto van al final, después de los obligatorios. def f(a=1, b) es un error de sintaxis; def f(b, a=1) es correcto.
¡Ojo!: nunca uses una lista (u otro mutable) como valor por defecto, como
def f(items=[]). Esa lista se crea una sola vez y queda compartida entre todas las llamadas, así que se va llenando sola de una a otra:def registrar_mal(nuevo, items=[]): items.append(nuevo) return items print(registrar_mal("Tornillos")) # ['Tornillos'] print(registrar_mal("Tuercas")) # ['Tornillos', 'Tuercas'] ← ¡no empezó vacía!Cada llamada hereda la basura de la anterior, aunque tú no le hayas pasado nada. Si necesitas una lista vacía por defecto, usa
Noney créala dentro:def registrar(nuevo: str, items: list | None = None) -> list: if items is None: items = [] items.append(nuevo) return itemsLa revisión va con el
is Nonedel Capítulo 6, no con un atajo tipoitems = items or []: una lista vacía que quien llama pasó a propósito también cuenta como “falsa”, y elorla reemplazaría en silencio.
Cuando el Argumento es un Estante Completo
El Capítulo 5 te enseñó el aliasing: dos etiquetas pueden apuntar al mismo estante. Ahora conecta ese cable con las funciones, porque pasar una lista a una función es exactamente eso: la función no recibe una copia, recibe otra etiqueta a TU estante.
def marcar_revision(pendientes: list) -> None:
pendientes.append("REVISAR") # esto muta el estante ORIGINAL
lote = ["Tornillos", "Tuercas"]
marcar_revision(lote)
print(lote) # ['Tornillos', 'Tuercas', 'REVISAR'] ← tu lista cambió
A veces es justo lo que quieres (así trabaja inventario.append(...) en el proyecto final). Pero cuando NO lo quieres, hay dos defensas: pasarle una copia (marcar_revision(lote.copy())) o, mejor, que la función devuelva una lista nueva en vez de mutar la que recibió, como hace eliminar_producto en el proyecto final. Los números, textos y tuplas están a salvo de esto: son inmutables, la función no puede alterarte el original.
Existe Más Vocabulario (y Queda Fuera)
Cuando leas código ajeno verás firmas como def f(*args, **kwargs) o llamadas tipo print(*lista). Son mecanismos para aceptar cantidades variables de argumentos. Funcionan, tienen su lugar, y este libro no los cubre: para todo lo que construimos aquí, los parámetros explícitos son más claros. Solo debes saber que existen para que no te desconcierten.