Acordeón de los Índices
Índice de los temas
- Python Functions
- Creating a Function
- Calling a Function
- Arguments
- Parameters or Arguments?
- Number of Arguments
- Arbitrary Arguments, *args
- Keyword Arguments
- Arbitrary Keyword Arguments, **kwargs
- Default Parameter Value
- Passing a List as an Argument
- Return Values
- The pass Statement
- Positional-Only Arguments
- Keyword-Only Arguments
- Combine Positional-Only and Keyword-Only
- Recursion
Python Functions
🐍 Funciones en Python: Bloques de Código Reutilizables
En Python, una función es un bloque de código organizado y reutilizable que se utiliza
para realizar una sola acción relacionada. Las funciones proporcionan una mejor
modularidad para tu aplicación y una gran cantidad de reutilización de código. Python te
ofrece muchas funciones incorporadas, como print()
, len()
,
etc., pero también puedes definir tus propias funciones para satisfacer tus necesidades.
¿Por Qué Usar Funciones?
- Organización del código: Las funciones ayudan a dividir programas grandes en bloques más pequeños y manejables, lo que facilita la lectura y comprensión del código.
- Reutilización del código: Una vez que defines una función, puedes llamarla (ejecutarla) tantas veces como necesites desde diferentes partes de tu programa, sin tener que reescribir el mismo código.
- Abstracción: Las funciones te permiten abstraer la lógica detrás de una tarea específica. No necesitas saber cómo funciona internamente una función para usarla; solo necesitas saber qué hace y qué argumentos (si los hay) espera.
- Reducción de la redundancia: Al encapsular código repetitivo en funciones, reduces la cantidad de código duplicado en tu programa, lo que lo hace más corto, más fácil de mantener y menos propenso a errores.
Tipos de Funciones en Python:
- Funciones Incorporadas (Built-in Functions): Son funciones que ya
están definidas en Python y listas para ser usadas sin necesidad de una definición
explícita. Ejemplos incluyen
print()
,type()
,max()
,min()
, etc. - Funciones Definidas por el Usuario (User-Defined Functions): Son funciones que los programadores crean para realizar tareas específicas según los requisitos de su programa.
En esta lección, nos centraremos principalmente en las funciones definidas por el usuario y cómo crearlas y utilizarlas eficazmente en Python.
Creating a Function
🛠️ Creando una Función en Python: La Sintaxis
Definir una función en Python es bastante sencillo. Se utiliza la palabra clave
def
, seguida del nombre de la función, paréntesis ()
que
pueden contener parámetros (entradas de la función), y finalmente dos puntos
:
. El bloque de código dentro de la función debe estar indentado.
Sintaxis Básica:
def nombre_de_la_funcion(parametros):
"""Docstring de la función (opcional pero recomendado)"""
# Cuerpo de la función: código a ejecutar
# ...
# return [valor] (opcional)
Elementos de la Definición de una Función:
def
: Palabra clave que indica el inicio de la definición de una función.nombre_de_la_funcion
: Es el identificador único que le das a tu función. Debe seguir las reglas de nomenclatura de las variables en Python (ej. no empezar con un número, no usar espacios, etc.). Se recomienda usar nombres descriptivos que indiquen qué hace la función.(parametros)
: Los parámetros son variables que se listan dentro de los paréntesis en la definición de la función. Son los valores que la función puede recibir como entrada para realizar sus operaciones. Una función puede no tener parámetros.:
: Los dos puntos marcan el final de la línea de definición de la función y el inicio del bloque de código indentado que constituye el cuerpo de la función."""Docstring de la función"""
: Una cadena de documentación (docstring) es una cadena literal que aparece como la primera sentencia en la definición de una función, módulo, clase o método. Se utiliza para documentar lo que hace la función, sus parámetros, y qué valor (si lo hay) devuelve. Es una práctica muy recomendada para hacer tu código más legible y mantenible.- Cuerpo de la función: Es el bloque de código indentado que contiene las sentencias que se ejecutarán cuando se llame a la función.
return [valor]
(opcional): La sentenciareturn
se utiliza para salir de la función y opcionalmente devolver un valor al que llamó a la función. Si no se incluye una sentenciareturn
, la función devuelve automáticamenteNone
.
Ejemplos de Definición de Funciones:
# Función sin parámetros que imprime un saludo
def saludar():
"""Imprime un saludo simple."""
print("¡Hola!")
# Función con un parámetro que saluda a una persona específica
def saludar_a(nombre):
"""Saluda a la persona con el nombre proporcionado."""
print(f"¡Hola, {nombre}!")
# Función con dos parámetros que suma dos números y devuelve el resultado
def sumar(a, b):
"""Suma dos números y devuelve la suma."""
suma = a + b
return suma
# Función sin sentencia return (devuelve None implícitamente)
def imprimir_info(mensaje):
"""Imprime un mensaje."""
print(mensaje)
Una vez que has definido una función, puedes usarla llamándola por su nombre seguido de paréntesis, pasando los argumentos necesarios si la función espera parámetros.
Calling a Function
📞 Llamando a una Función: Poniéndola en Acción
Para ejecutar el código dentro de una función, necesitas llamarla. La
forma de llamar a una función es escribir su nombre seguido de paréntesis
()
. Si la función espera argumentos (parámetros), debes pasarlos dentro de
los paréntesis en el momento de la llamada.
Sintaxis para Llamar a una Función:
nombre_de_la_funcion() # Si la función no tiene parámetros
nombre_de_la_funcion(argumento1, argumento2, ...) # Si la función tiene parámetros
Ejemplos de Llamadas a Funciones:
Basándonos en las funciones que definimos en el tema anterior:
# Llamando a la función saludar (sin parámetros)
saludar()
# Output: ¡Hola!
# Llamando a la función saludar_a (con un argumento)
saludar_a("Ana")
saludar_a("Carlos")
# Output:
# ¡Hola, Ana!
# ¡Hola, Carlos!
# Llamando a la función sumar (con dos argumentos) y guardando el resultado
resultado_suma = sumar(5, 3)
print(f"La suma es: {resultado_suma}")
# Output: La suma es: 8
# Llamando a la función imprimir_info (con un argumento)
imprimir_info("Este es un mensaje.")
# Output: Este es un mensaje.
Puntos Importantes al Llamar Funciones:
- Orden de los argumentos: Al llamar a una función, los argumentos que pasas deben coincidir con el orden de los parámetros definidos en la función, a menos que utilices argumentos de palabra clave (que veremos más adelante).
- Número de argumentos: Generalmente, debes proporcionar el mismo número de argumentos que parámetros espera la función. Sin embargo, Python ofrece mecanismos para manejar un número variable de argumentos o argumentos con valores por defecto.
- Valor de retorno: Si una función tiene una sentencia
return
, la llamada a la función devolverá el valor especificado. Puedes usar este valor en otras operaciones, asignarlo a una variable, o imprimirlo directamente. Si no hay unreturn
explícito, la función devuelveNone
.
Llamar a una función es lo que realmente ejecuta el código que has definido dentro de ella. Es la forma de reutilizar y organizar tu lógica de programación de manera eficiente.
Arguments
➡️ Argumentos en Funciones: La Información de Entrada
Cuando llamas a una función, puedes pasarle valores. Estos valores son los **argumentos**. Los argumentos se corresponden con los **parámetros** definidos en la función. Los argumentos permiten que las funciones operen con diferentes datos cada vez que son llamadas, haciéndolas más flexibles y poderosas.
Tipos de Argumentos:
En Python, al llamar a una función, los argumentos se pueden pasar de diferentes maneras:
- Argumentos Posicionales: Son los argumentos que se pasan a una función en el mismo orden en que se definieron los parámetros. La correspondencia se basa en la posición.
- Argumentos de Palabra Clave (Keyword Arguments): Son argumentos que se pasan a una función especificando el nombre del parámetro al que se debe asignar el valor. Esto permite pasar argumentos fuera de orden y hace que la llamada a la función sea más legible.
Ejemplos de Argumentos:
def describir_persona(nombre, edad, ciudad):
"""Describe a una persona con su nombre, edad y ciudad."""
print(f"Nombre: {nombre}, Edad: {edad}, Ciudad: {ciudad}")
# Llamada con argumentos posicionales
describir_persona("Alicia", 30, "Madrid")
# Output: Nombre: Alicia, Edad: 30, Ciudad: Madrid
# Llamada con argumentos de palabra clave (el orden no importa)
describir_persona(edad=25, ciudad="Barcelona", nombre="Beto")
# Output: Nombre: Beto, Edad: 25, Ciudad: Barcelona
# Combinación de argumentos posicionales y de palabra clave
# Los argumentos posicionales deben ir primero
describir_persona("Carla", edad=35, ciudad="Valencia")
# Output: Nombre: Carla, Edad: 35, Ciudad: Valencia
# ¡Cuidado! Un argumento posicional después de uno de palabra clave genera un error:
# describir_persona(nombre="Diana", 40, "Sevilla") # Esto daría un SyntaxError
Consideraciones sobre los Argumentos:
- Al usar argumentos posicionales, asegúrate de mantener el orden correcto definido en la función.
- Los argumentos de palabra clave son muy útiles para funciones con muchos parámetros, ya que mejoran la claridad de la llamada.
- Puedes combinar argumentos posicionales y de palabra clave, pero los argumentos posicionales deben preceder a los argumentos de palabra clave.
Comprender cómo pasar argumentos a tus funciones es fundamental para hacerlas versátiles y adaptables a diferentes situaciones.
Parameters or Arguments?
🤔 ¿Parámetros o Argumentos? ¡A Clarificar la Confusión!
A menudo, los términos "parámetro" y "argumento" se usan indistintamente, pero en el contexto de las funciones, tienen significados ligeramente diferentes. Entender esta distinción puede ayudarte a ser más preciso al hablar y escribir sobre funciones.
Definiciones Clave:
- Parámetro: Un parámetro es una variable listada dentro de los paréntesis en la definición de la función. Es un nombre que se utiliza dentro de la función para referirse a un valor que se espera recibir cuando se llame a la función. Piensa en los parámetros como los "marcadores de posición" para los valores que la función va a utilizar.
- Argumento: Un argumento es el valor real que se pasa a la función cuando se la llama. Es el dato concreto que se proporciona al parámetro de la función. Piensa en los argumentos como los "valores reales" que se colocan en esos marcadores de posición.
Analogía para Recordar:
Imagina que estás horneando una tarta. La receta podría decir:
def hornear_tarta(harina, azucar, huevos):
# ... instrucciones para hornear ...
return tarta
En este caso, harina
, azucar
y huevos
son los
parámetros de la función hornear_tarta
. Son los
ingredientes que la función espera recibir.
Cuando realmente horneas la tarta, podrías llamar a la función así:
mi_tarta = hornear_tarta("200g de harina", "150g de azucar", 3)
Aquí, "200g de harina"
, "150g de azucar"
y 3
son
los argumentos que estás pasando a la función. Son los valores
específicos que se asignan a los parámetros correspondientes.
En Resumen:
- Los parámetros se definen en la cabecera de la función.
- Los argumentos se pasan al llamar a la función.
- Los argumentos se asignan a los parámetros según su posición o por nombre (en el caso de los argumentos de palabra clave).
Aunque la distinción puede parecer pequeña, es útil para entender con precisión la documentación y las discusiones sobre funciones en Python y otros lenguajes de programación.
Number of Arguments
🔢 Número de Argumentos: Flexibilidad en las Llamadas
Al definir una función en Python, especificas el número de parámetros que espera recibir. Cuando llamas a la función, normalmente debes proporcionar el número correcto de argumentos. Sin embargo, Python ofrece varias formas de hacer que tus funciones sean más flexibles en cuanto al número de argumentos que pueden aceptar.
Número Fijo de Argumentos:
La forma más común es definir una función con un número fijo de parámetros. En este caso, al llamar a la función, debes pasar exactamente el mismo número de argumentos.
def potencia(base, exponente):
"""Calcula la base elevada al exponente."""
resultado = base ** exponente
print(f"{base} elevado a {exponente} es {resultado}")
potencia(2, 3) # Correcto: se pasan dos argumentos
# potencia(5) # Error: falta un argumento
# potencia(2, 3, 4) # Error: sobran argumentos
Funciones con un Número Variable de Argumentos:
Python permite definir funciones que pueden aceptar un número variable de argumentos. Esto es útil cuando no sabes de antemano cuántos argumentos se pasarán a la función.
*args
(Argumentos Posicionales Variables): Si precedes el último parámetro en la definición de la función con un asterisco (*
), se recogerán todos los argumentos posicionales adicionales en una tupla con ese nombre (convencionalmenteargs
).**kwargs
(Argumentos de Palabra Clave Variables): Si precedes el último parámetro con dos asteriscos (**
), se recogerán todos los argumentos de palabra clave adicionales en un diccionario con ese nombre (convencionalmentekwargs
).
Ejemplos de Número Variable de Argumentos:
# Función que acepta un número variable de argumentos posicionales
def sumar_todos(*numeros):
"""Suma todos los números pasados como argumentos."""
suma = 0
for num in numeros:
suma += num
return suma
print(sumar_todos(1, 2, 3)) # Output: 6
print(sumar_todos(10, 20, 30, 40)) # Output: 100
print(sumar_todos()) # Output: 0 (no se pasaron argumentos)
# Función que acepta un número variable de argumentos de palabra clave
def mostrar_info(**info):
"""Muestra la información pasada como argumentos de palabra clave."""
for llave, valor in info.items():
print(f"{llave}: {valor}")
mostrar_info(nombre="Elena", edad=28, ciudad="México")
# Output:
# nombre: Elena
# edad: 28
# ciudad: México
mostrar_info(idioma="Español", nivel="Avanzado")
# Output:
# idioma: Español
# nivel: Avanzado
# Función que combina argumentos posicionales y de palabra clave variables
def funcion_flexible(primero, *otros_posicionales, **otros_clave):
"""Ejemplo de función con diferentes tipos de argumentos."""
print(f"Primer argumento: {primero}")
print(f"Otros posicionales: {otros_posicionales}")
print(f"Otros de clave: {otros_clave}")
funcion_flexible(1, 2, 3, nombre="Luis", profesion="Ingeniero")
# Output:
# Primer argumento: 1
# Otros posicionales: (2, 3)
# Otros de clave: {'nombre': 'Luis', 'profesion': 'Ingeniero'}
El uso de *args
y **kwargs
proporciona una gran flexibilidad al
diseñar funciones que necesitan manejar un número indeterminado de entradas.
Arbitrary Arguments, *args
⭐ Argumentos Arbitrarios Posicionales: *args
al Rescate
En Python, a veces no sabes de antemano cuántos argumentos posicionales se pasarán a tu
función. En lugar de definir parámetros individuales para cada posible argumento, puedes
usar la sintaxis de *args
. Esto permite que tu función reciba un número
variable de argumentos posicionales.
¿Cómo Funciona *args
?
Cuando defines un parámetro con un asterisco (*
) delante, como
*args
, Python empaqueta todos los argumentos posicionales que se pasan a la
función en una tupla llamada args
(puedes usar otro
nombre, pero args
es la convención).
Ejemplo de Uso de *args
:
def imprimir_ingredientes(*ingredientes):
"""Imprime cada ingrediente pasado a la función."""
print("Ingredientes:")
for ingrediente in ingredientes:
print(f"- {ingrediente}")
imprimir_ingredientes("harina", "azúcar", "huevos")
# Output:
# Ingredientes:
# - harina
# - azúcar
# - huevos
imprimir_ingredientes("manzana", "canela")
# Output:
# Ingredientes:
# - manzana
# - canela
imprimir_ingredientes()
# Output:
# Ingredientes:
Puntos Clave sobre *args
:
*args
recoge solo los argumentos posicionales que no se corresponden con parámetros definidos explícitamente.- La variable
args
dentro de la función es una tupla, por lo que puedes iterar sobre ella, acceder a sus elementos por índice, etc. - Puedes tener otros parámetros definidos antes de
*args
. Los argumentos posicionales que se pasen primero se asignarán a estos parámetros, y el resto se empaquetará en la tuplaargs
. - Si la función se llama sin ningún argumento posicional adicional, la tupla
args
estará vacía.
Ejemplo Combinando Parámetros Regulares y *args
:
def saludar_a_varios(saludo, *nombres):
"""Saluda a varias personas con un saludo específico."""
for nombre in nombres:
print(f"{saludo}, {nombre}!")
saludar_a_varios("Hola", "Ana", "Carlos", "Sofía")
# Output:
# Hola, Ana!
# Hola, Carlos!
# Hola, Sofía!
*args
es una herramienta poderosa para crear funciones que son flexibles en
cuanto al número de argumentos posicionales que pueden recibir, lo que puede hacer tu
código más adaptable y reutilizable.
Keyword Arguments
🏷️ Argumentos de Palabra Clave: Claridad y Flexibilidad al Llamar
Los argumentos de palabra clave (keyword arguments) son una forma de pasar argumentos a una función especificando el nombre del parámetro al que se debe asignar el valor. Esto tiene varias ventajas:
- Mayor legibilidad: Al incluir el nombre del parámetro en la llamada, queda más claro qué representa cada valor que se está pasando.
- Orden flexible: No necesitas recordar el orden exacto de los parámetros definidos en la función, ya que puedes pasar los argumentos en cualquier orden especificando el nombre del parámetro correspondiente.
- Omisión de parámetros con valores por defecto: Puedes optar por no pasar argumentos para los parámetros que tienen valores por defecto definidos en la función.
Sintaxis de los Argumentos de Palabra Clave:
Al llamar a una función, utilizas la siguiente sintaxis para pasar argumentos de palabra clave:
nombre_de_la_funcion(nombre_parametro1=valor1, nombre_parametro2=valor2, ...)
Ejemplo de Uso de Argumentos de Palabra Clave:
def describir_animal(tipo, nombre, color="marrón"):
"""Describe un animal con su tipo, nombre y color (por defecto marrón)."""
print(f"Tipo: {tipo}, Nombre: {nombre}, Color: {color}")
# Llamada usando solo argumentos posicionales
describir_animal("perro", "Firulais")
# Output: Tipo: perro, Nombre: Firulais, Color: marrón
# Llamada usando argumentos de palabra clave (orden diferente)
describir_animal(nombre="Kitty", tipo="gato", color="blanco")
# Output: Tipo: gato, Nombre: Kitty, Color: blanco
# Llamada combinando argumento posicional y de palabra clave
describir_animal("pez", nombre="Nemo", color="naranja")
# Output: Tipo: pez, Nombre: Nemo, Color: naranja
# Llamada omitiendo el argumento para el parámetro con valor por defecto
describir_animal(tipo="pájaro", nombre="Piolín")
# Output: Tipo: pájaro, Nombre: Piolín, Color: marrón
Reglas al Usar Argumentos de Palabra Clave:
- Si combinas argumentos posicionales y de palabra clave en una llamada a función, los argumentos posicionales deben ir primero.
- El nombre de la palabra clave debe coincidir exactamente con uno de los nombres de los parámetros definidos en la función.
- No puedes asignar un valor a un mismo parámetro más de una vez en una llamada a función (ni como argumento posicional seguido de un argumento de palabra clave, ni con dos argumentos de palabra clave para el mismo parámetro).
Los argumentos de palabra clave son una herramienta valiosa para hacer que las llamadas a tus funciones sean más claras y flexibles, especialmente cuando las funciones tienen muchos parámetros opcionales.
Arbitrary Keyword Arguments, **kwargs
⭐ Argumentos Arbitrarios de Palabra Clave:
**kwargs
para la Flexibilidad Nominal
Al igual que *args
permite a una función aceptar un número variable de
argumentos posicionales, **kwargs
permite a una función aceptar un número
variable de argumentos de palabra clave. Esto es útil cuando quieres
que tu función pueda recibir información adicional sin haber definido explícitamente
todos los posibles parámetros.
¿Cómo Funciona **kwargs
?
Cuando defines un parámetro con dos asteriscos (**
) delante, como
**kwargs
, Python recoge todos los argumentos de palabra clave adicionales
que se pasan a la función en un diccionario llamado kwargs
(nuevamente, puedes usar otro nombre, pero kwargs
es la convención).
Ejemplo de Uso de **kwargs
:
def mostrar_detalles(**detalles):
"""Imprime los detalles pasados como argumentos de palabra clave."""
print("Detalles:")
for clave, valor in detalles.items():
print(f"- {clave}: {valor}")
mostrar_detalles(nombre="Ricardo", profesion="Desarrollador", edad=35)
# Output:
# Detalles:
# - nombre: Ricardo
# - profesion: Desarrollador
# - edad: 35
mostrar_detalles(ciudad="Buenos Aires", pais="Argentina")
# Output:
# Detalles:
# - ciudad: Buenos Aires
# - pais: Argentina
mostrar_detalles()
# Output:
# Detalles:
Puntos Clave sobre **kwargs
:
**kwargs
recoge solo los argumentos de palabra clave que no se corresponden con parámetros definidos explícitamente.- La variable
kwargs
dentro de la función es un diccionario, donde las claves son los nombres de los parámetros pasados y los valores son los argumentos correspondientes. - Puedes tener otros parámetros definidos antes de
**kwargs
(incluyendo*args
). - Si la función se llama sin ningún argumento de palabra clave adicional, el
diccionario
kwargs
estará vacío.
Ejemplo Combinando Parámetros Regulares, *args
y **kwargs
:
def funcion_compleja(requerido, *args, opcional="valor_por_defecto", **kwargs):
"""Ejemplo de función con varios tipos de argumentos."""
print(f"Requerido: {requerido}")
print(f"Args: {args}")
print(f"Opcional: {opcional}")
print(f"Kwargs: {kwargs}")
funcion_compleja("dato", 1, 2, extra="info", otra="cosa")
# Output:
# Requerido: dato
# Args: (1, 2)
# Opcional: valor_por_defecto
# Kwargs: {'extra': 'info', 'otra': 'cosa'}
funcion_compleja("otro", opcional="nuevo_valor", llave="uno", llave2="dos")
# Output:
# Requerido: otro
# Args: ()
# Opcional: nuevo_valor
# Kwargs: {'llave': 'uno', 'llave2': 'dos'}
**kwargs
es increíblemente útil para crear funciones que pueden aceptar una
amplia gama de opciones o configuraciones sin necesidad de definir cada una de ellas
explícitamente en la firma de la función.
Default Parameter Value
⚙️ Valores por Defecto de los Parámetros: Haciendo Parámetros Opcionales
En Python, puedes especificar un valor por defecto para uno o más parámetros de una función. Si al llamar a la función no se proporciona un argumento para un parámetro con valor por defecto, se utilizará ese valor predeterminado. Esto hace que esos parámetros sean opcionales.
Sintaxis para Definir Valores por Defecto:
Para asignar un valor por defecto a un parámetro, simplemente usa el operador de
asignación (=
) en la definición de la función:
def nombre_de_la_funcion(parametro1, parametro2=valor_por_defecto, parametro3=otro_valor_por_defecto):
# Cuerpo de la función
# ...
Ejemplo de Uso de Valores por Defecto:
def saludar(nombre, saludo="¡Hola!"):
"""Saluda a una persona con un saludo específico (por defecto '¡Hola!')."""
print(f"{saludo}, {nombre}!")
saludar("Laura") # Se usa el valor por defecto para 'saludo'
# Output: ¡Hola!, Laura!
saludar("Marcos", "¡Buenos días!") # Se proporciona un valor para 'saludo'
# Output: ¡Buenos días!, Marcos!
def calcular_area_rectangulo(ancho, alto=10):
"""Calcula el área de un rectángulo (alto por defecto es 10)."""
area = ancho * alto
print(f"El área del rectángulo es: {area}")
calcular_area_rectangulo(5) # Se usa el valor por defecto para 'alto' (5 * 10 = 50)
# Output: El área del rectángulo es: 50
calcular_area_rectangulo(5, 20) # Se proporciona un valor para 'alto' (5 * 20 = 100)
# Output: El área del rectángulo es: 100
Reglas al Usar Valores por Defecto:
- Los parámetros con valores por defecto deben definirse al final de la lista de parámetros. Los parámetros sin valores por defecto deben ir primero. Intentar definir un parámetro sin valor por defecto después de uno con valor por defecto generará un error de sintaxis.
# Esto es correcto:
def funcion_correcta(a, b=1, c=2):
print(f"a={a}, b={b}, c={c}")
# Esto genera un SyntaxError:
# def funcion_incorrecta(a=1, b, c=2):
# print(f"a={a}, b={b}, c={c}")
None
como valor por defecto y luego crear
el objeto mutable dentro de la función si es necesario.
def agregar_a_lista_incorrecto(elemento, lista=[]):
"""¡Cuidado! El valor por defecto mutable se comparte entre llamadas."""
lista.append(elemento)
print(lista)
agregar_a_lista_incorrecto(1) # Output: [1]
agregar_a_lista_incorrecto(2) # Output: [1, 2] (¡Se esperaba [2]!)
def agregar_a_lista_correcto(elemento, lista=None):
"""Forma correcta de manejar valores por defecto mutables."""
if lista is None:
lista = []
lista.append(elemento)
print(lista)
agregar_a_lista_correcto(1) # Output: [1]
agregar_a_lista_correcto(2) # Output: [2] (¡Ahora sí!)
Los valores por defecto de los parámetros son una forma poderosa de hacer tus funciones más versátiles y fáciles de usar, permitiendo que se adapten a diferentes escenarios con menos necesidad de pasar todos los argumentos explícitamente.
Passing a List as an Argument
Pasando una Lista como Argumento: Trabajando con Colecciones
En Python, puedes pasar listas (y otras colecciones como tuplas, diccionarios, conjuntos) como argumentos a las funciones. Cuando haces esto, la función puede acceder a los elementos de la lista y realizar operaciones sobre ellos.
Ejemplo Básico:
Considera una función que imprime todos los elementos de una lista:
def imprimir_lista(mi_lista):
"""Imprime cada elemento de la lista."""
for elemento in mi_lista:
print(elemento)
frutas = ["manzana", "banana", "cereza"]
imprimir_lista(frutas)
# Output:
# manzana
# banana
# cereza
Modificando Listas Dentro de Funciones: ¡Cuidado con los Efectos Secundarios!
Es importante entender que cuando pasas una lista como argumento a una función, lo que se pasa es una referencia al objeto de la lista en memoria. Esto significa que si la función modifica la lista, esos cambios se reflejarán en la lista original fuera de la función.
def agregar_elemento(mi_lista, elemento):
"""Agrega un elemento al final de la lista."""
mi_lista.append(elemento)
numeros = [1, 2, 3]
print(f"Lista original: {numeros}")
agregar_elemento(numeros, 4)
print(f"Lista después de la función: {numeros}")
# Output:
# Lista original: [1, 2, 3]
# Lista después de la función: [1, 2, 3, 4]
def duplicar_elementos(mi_lista):
"""Duplica cada elemento de la lista."""
for i in range(len(mi_lista)):
mi_lista[i] *= 2
valores = [5, 10, 15]
print(f"Lista original: {valores}")
duplicar_elementos(valores)
print(f"Lista después de la función: {valores}")
# Output:
# Lista original: [5, 10, 15]
# Lista después de la función: [10, 20, 30]
Evitando la Modificación Inesperada: Creando Copias
Si no quieres que la función modifique la lista original, puedes pasar una copia de la
lista en lugar de la referencia. Puedes hacer esto utilizando el método
.copy()
o la notación de slicing [:]
.
def no_modificar_lista(mi_lista):
"""Intenta modificar la lista (pero trabaja con una copia)."""
copia_lista = mi_lista.copy()
copia_lista.append("nuevo elemento")
print(f"Lista dentro de la función: {copia_lista}")
letras = ["a", "b", "c"]
print(f"Lista original: {letras}")
no_modificar_lista(letras)
print(f"Lista después de la función: {letras}")
# Output:
# Lista original: ['a', 'b', 'c']
# Lista dentro de la función: ['a', 'b', 'c', 'nuevo elemento']
# Lista después de la función: ['a', 'b', 'c'] (¡No se modificó!)
Pasar listas como argumentos es una forma poderosa de trabajar con colecciones de datos dentro de las funciones. Sin embargo, es crucial ser consciente de si deseas o no modificar la lista original y tomar las precauciones necesarias (como crear copias) para evitar efectos secundarios no deseados.
Return Values
📤 Valores de Retorno: La Respuesta de la Función
La sentencia return
se utiliza dentro de una función para finalizar su
ejecución y, opcionalmente, devolver un valor al código que llamó a la función. Este
valor de retorno puede ser de cualquier tipo de dato en Python (un número, una cadena,
una lista, un diccionario, etc.).
Sintaxis de return
:
def mi_funcion(parametros):
# ... código de la función ...
return valor_a_devolver
Si no se incluye una sentencia return
en una función, o si se usa
return
sin ningún valor, la función devolverá automáticamente
None
.
Ejemplos de Funciones con Valores de Retorno:
def multiplicar(a, b):
"""Multiplica dos números y devuelve el resultado."""
resultado = a * b
return resultado
producto = multiplicar(5, 4)
print(f"El producto es: {producto}")
# Output: El producto es: 20
def obtener_nombre_completo(nombre, apellido):
"""Concatena nombre y apellido y devuelve el nombre completo."""
nombre_completo = f"{nombre} {apellido}"
return nombre_completo.strip()
nombre = obtener_nombre_completo("Juan", "Pérez")
print(f"Nombre completo: {nombre}")
# Output: Nombre completo: Juan Pérez
def es_par(numero):
"""Verifica si un número es par y devuelve True o False."""
if numero % 2 == 0:
return True
else:
return False
print(f"¿Es 10 par? {es_par(10)}")
print(f"¿Es 7 par? {es_par(7)}")
# Output:
# ¿Es 10 par? True
# ¿Es 7 par? False
def dividir(dividendo, divisor):
"""Divide dos números y devuelve el cociente y el resto."""
if divisor == 0:
return "Error: No se puede dividir por cero", None
cociente = dividendo // divisor
resto = dividendo % divisor
return cociente, resto # Devuelve una tupla
resultado_division = dividir(15, 4)
print(f"Cociente y resto: {resultado_division}")
cociente, resto = dividir(20, 3)
print(f"Cociente: {cociente}, Resto: {resto}")
# Output:
# Cociente y resto: (3, 3)
# Cociente: 6, Resto: 2
def obtener_info_persona(nombre, edad=None, ciudad="Desconocida"):
"""Devuelve un diccionario con la información de la persona."""
info = {"nombre": nombre}
if edad is not None:
info["edad"] = edad
info["ciudad"] = ciudad
return info
persona1 = obtener_info_persona("Ana", 30)
persona2 = obtener_info_persona("Carlos", ciudad="Madrid")
persona3 = obtener_info_persona("Sofía")
print(persona1)
print(persona2)
print(persona3)
# Output:
# {'nombre': 'Ana', 'edad': 30, 'ciudad': 'Desconocida'}
# {'nombre': 'Carlos', 'ciudad': 'Madrid'}
# {'nombre': 'Sofía', 'ciudad': 'Desconocida'}
Puntos Clave sobre los Valores de Retorno:
- Una función puede tener múltiples sentencias
return
, pero solo se ejecutará la primera que se alcance, finalizando la función. - Puedes devolver cualquier tipo de dato o combinación de datos (como una tupla o un diccionario).
- Si una función no tiene una sentencia
return
explícita, devuelveNone
. - El valor de retorno de una función puede ser utilizado directamente en expresiones, asignado a variables o pasado como argumento a otra función.
Los valores de retorno son esenciales para que las funciones puedan producir resultados y comunicar información al resto de tu programa, permitiendo la creación de código modular y reutilizable.
The pass Statement
🚦 La Sentencia pass
: Un Marcador de Posición
La sentencia pass
en Python es una operación nula; nada sucede cuando se
ejecuta. Aunque no realiza ninguna acción, es útil en situaciones donde la sintaxis de
Python requiere una declaración (como dentro de un bloque de código de una función o una
estructura condicional), pero aún no has implementado la lógica para ese bloque.
Uso en Funciones:
En el contexto de las funciones, pass
se utiliza a menudo como un marcador
de posición cuando estás definiendo la estructura de tu programa pero aún no has escrito
el código para una función específica. Esto te permite evitar errores de sintaxis.
Ejemplo de pass
en una Función:
def funcion_pendiente():
"""Esta función se implementará más tarde."""
pass
# Puedes llamar a la función sin que cause un error
funcion_pendiente()
print("El programa continúa...")
# Output: El programa continúa...
¿Por Qué Usar pass
en Funciones?
- Evitar errores de sintaxis: Python requiere que los bloques de
código (como el cuerpo de una función) contengan al menos una sentencia. Si defines
una función pero aún no tienes el código para ella, usar
pass
evita un errorIndentationError
o similar. - Planificación y estructura: Puedes usar
pass
para esbozar la estructura de tu programa, definiendo los nombres de las funciones que necesitarás, y luego volver a implementar la lógica dentro de ellas más tarde. - Interfaces o clases abstractas (implícitas): Aunque Python no tiene
interfaces explícitas como otros lenguajes, a veces se usa
pass
en métodos de clases base que se espera que las subclases implementen.
En resumen:
pass
es una sentencia que no hace nada. Es útil como un marcador de posición
en bloques de código donde se requiere una sentencia por la sintaxis de Python, pero aún
no tienes la implementación real.
Positional-Only Arguments
📍 Argumentos Solo Posicionales: Forzando el Orden al Llamar
Python permite definir funciones donde ciertos parámetros deben ser proporcionados solo posicionalmente. Esto significa que al llamar a la función, los argumentos para estos parámetros no pueden especificarse usando el nombre del parámetro (argumentos de palabra clave); deben proporcionarse en el orden en que se definieron.
Sintaxis para Argumentos Solo Posicionales:
Para especificar argumentos solo posicionales, se utiliza una barra inclinada
(/
) en la lista de parámetros de la definición de la función. Los
parámetros que aparecen antes de la /
son solo posicionales.
def mi_funcion(posicional_obligatorio, otro_posicional_obligatorio, /, posicional_o_de_palabra_clave, otro_mas):
# ... cuerpo de la función ...
En este ejemplo, posicional_obligatorio
y
otro_posicional_obligatorio
solo pueden pasarse por posición.
posicional_o_de_palabra_clave
y otro_mas
pueden pasarse tanto
por posición como por palabra clave.
Si no hay otros parámetros que puedan ser de palabra clave, la barra inclinada se coloca después de los argumentos solo posicionales:
def otra_funcion(solo_pos1, solo_pos2, /):
# ... cuerpo de la función ...
Ejemplo de Uso de Argumentos Solo Posicionales:
def dividir_solo_posicional(dividendo, divisor, /, mostrar_resultado=True):
"""Divide dos números (solo posicionales) y opcionalmente muestra el resultado."""
resultado = dividendo / divisor
if mostrar_resultado:
print(f"El resultado de {dividendo} / {divisor} es {resultado}")
return resultado
# Llamadas válidas (solo posicionales para los dos primeros argumentos)
resultado1 = dividir_solo_posicional(10, 2)
resultado2 = dividir_solo_posicional(20, 5, mostrar_resultado=False)
# Llamadas inválidas (intentando usar nombres de parámetros para argumentos solo posicionales)
# dividir_solo_posicional(dividendo=15, divisor=3) # Genera un TypeError
# dividir_solo_posicional(18, divisor=6) # Genera un TypeError
print(f"Resultado 1: {resultado1}")
print(f"Resultado 2: {resultado2}")
# Output:
# El resultado de 10 / 2 es 5.0
# Resultado 1: 5.0
# Resultado 2: 4.0
< ¿Por Qué Usar Argumentos Solo Posicionales?
- Claridad e intención: Puede hacer más claro que los primeros argumentos son fundamentales y su significado está determinado por su posición.
- API más limpia: Permite que el nombre de los parámetros en la definición de la función sea más abstracto o incluso se pueda cambiar en implementaciones futuras sin romper el código de llamada (ya que los usuarios no dependen de los nombres).
- Prevención de ambigüedad: En funciones con muchos parámetros, puede evitar confusiones sobre qué argumento corresponde a qué parámetro, especialmente si los nombres podrían ser similares o poco claros.
- Compatibilidad con funciones incorporadas: Muchas funciones
incorporadas de Python (como
min()
,max()
,pow()
) utilizan argumentos solo posicionales. Usar esta misma convención en tus propias funciones puede hacerlas más consistentes con el estilo de Python. - La decisión de usar argumentos solo posicionales debe basarse en el diseño de la API de tu función y en cómo esperas que los usuarios la utilicen.
- No abuses de esta característica; úsala cuando realmente aporte claridad o beneficie el mantenimiento de tu código.
Consideraciones:
Los argumentos solo posicionales son una herramienta poderosa para refinar la interfaz de tus funciones y controlar cómo se deben pasar los argumentos, lo que puede llevar a un código más robusto y fácil de entender.
Keyword-Only Arguments
🏷️ Argumentos Solo de Palabra Clave: Exigiendo Claridad al Llamar
Los argumentos solo de palabra clave (keyword-only arguments) son parámetros en la definición de una función que solo pueden ser pasados utilizando la sintaxis de palabra clave (es decir, especificando el nombre del parámetro al llamar a la función). Esto obliga a que las llamadas a la función sean más explícitas y legibles, especialmente cuando la función tiene muchos parámetros opcionales o cuando el orden de los argumentos no es intuitivo.
Sintaxis para Argumentos Solo de Palabra Clave:
Para definir argumentos solo de palabra clave, se coloca un asterisco
(*
) en
la lista de parámetros de la definición de la función. Cualquier parámetro que
aparezca
después del asterisco se considera solo de palabra clave.
def mi_funcion(*, kw_solo_obligatorio, otro_kw_solo=valor_defecto):
# ... cuerpo de la función ...
En este ejemplo, kw_solo_obligatorio
debe ser pasado usando su nombre
(ej.,
kw_solo_obligatorio=valor
), y otro_kw_solo
también debe
pasarse por nombre, aunque tiene un valor por defecto y es opcional.
También puedes tener argumentos solo de palabra clave después de parámetros regulares
o
*args
:
def otra_funcion(arg_posicional, *args, kw_solo1, kw_solo2="algo"):
# ... cuerpo de la función ...
Ejemplo de Uso de Argumentos Solo de Palabra Clave:
def configurar_alarma(hora, minuto, *, repetir=False, sonido="bip"):
"""Configura una alarma con hora, minuto (posicionales) y opciones (solo de palabra clave)."""
print(f"Alarma configurada para las {hora}:{minuto}, repetir: {repetir}, sonido: {sonido}")
# Llamadas válidas (hora y minuto son posicionales, repetir y sonido son solo de palabra clave)
configurar_alarma(10, 30, repetir=True, sonido="campana")
configurar_alarma(12, 0) # 'repetir' usa su valor por defecto (False), 'sonido' también ("bip")
configurar_alarma(6, 45, sonido="melodía") # 'repetir' usa su valor por defecto
# Llamadas inválidas (intentando usar argumentos posicionales para los parámetros solo de palabra clave)
# configurar_alarma(9, 0, True, "alarma") # Genera un TypeError
# configurar_alarma(11, 15, repetir=True, "zumbido") # Genera un TypeError
¿Por Qué Usar Argumentos Solo de Palabra Clave?
- Mayor claridad: Cuando una función tiene muchos parámetros booleanos o de cadena que actúan como opciones, usar argumentos solo de palabra clave hace que la llamada sea mucho más legible, ya que se indica explícitamente qué opción se está configurando.
- Evolución de la API: Permite cambiar el orden de los parámetros en la definición de la función sin romper el código de llamada, ya que los usuarios dependen de los nombres y no de la posición para los argumentos solo de palabra clave.
- Mejor documentación implícita: La necesidad de usar el nombre del parámetro al llamar a la función actúa como una forma de documentación, recordando al usuario el propósito de cada argumento.
Consideraciones:
- Usa argumentos solo de palabra clave para parámetros que no tienen un orden obvio o que actúan como opciones configurables.
- Asegúrate de que los nombres de los parámetros sean descriptivos para que la llamada a la función sea clara.
Los argumentos solo de palabra clave son una herramienta valiosa para diseñar interfaces de función robustas y fáciles de usar, especialmente en funciones complejas con múltiples opciones.
Combine Positional-Only and Keyword-Only
🤝 Combinando Argumentos Solo Posicionales y Solo de Palabra Clave: Un Control Total
Python nos brinda la flexibilidad de definir funciones que tienen tanto argumentos
que
deben ser pasados solo por posición como argumentos que deben ser pasados solo por
palabra clave. Esto se logra utilizando tanto la barra inclinada (/
)
como
el asterisco (*
) en la lista de parámetros de la definición de la
función.
Sintaxis para Combinar Tipos de Argumentos:
La sintaxis general para definir una función que utiliza ambos tipos de argumentos es la siguiente:
def mi_funcion(solo_pos1, solo_pos2, /, pos_o_kw1, *, solo_kw1, solo_kw2=valor_defecto):
# ... cuerpo de la función ...
En esta definición:
solo_pos1
ysolo_pos2
deben ser pasados por posición.pos_o_kw1
puede ser pasado tanto por posición como por palabra clave.- El
*
actúa como un delimitador. solo_kw1
ysolo_kw2
(que tiene un valor por defecto) deben ser pasados por palabra clave.
Ejemplo de Combinación:
def procesar_pedido(producto_id, cantidad, /, cliente_email, *, envio_urgente=False, direccion_envio):
"""
Procesa un pedido.
Los primeros dos argumentos (producto_id, cantidad) son solo posicionales.
cliente_email puede ser posicional o de palabra clave.
envio_urgente y direccion_envio son solo de palabra clave.
"""
print(f"Procesando pedido para el producto {producto_id}, cantidad: {cantidad}")
print(f"Email del cliente: {cliente_email}")
print(f"Envío urgente: {envio_urgente}")
print(f"Dirección de envío: {direccion_envio}")
# ... lógica para procesar el pedido ...
# Llamadas válidas:
procesar_pedido(123, 2, "cliente@email.com", envio_urgente=True, direccion_envio="Calle Falsa 123")
procesar_pedido(456, 1, cliente_email="otro@email.com", direccion_envio="Avenida Principal 456")
procesar_pedido(789, 3, "tercero@email.com", direccion_envio="Plaza Central s/n")
# Llamadas inválidas:
# procesar_pedido(producto_id=123, cantidad=2, "cliente@email.com", envio_urgente=True, direccion_envio="...") # TypeError
# procesar_pedido(123, cantidad=2, cliente_email="...", envio_urgente=True, direccion_envio="...") # TypeError
# procesar_pedido(123, 2, "...", True, direccion_envio="...") # TypeError (True para un argumento solo de palabra clave)
# procesar_pedido(123, 2, "...", envio_urgente=True, "...") # TypeError (falta el nombre del argumento solo de palabra clave)
Beneficios de la Combinación:
- Claridad para argumentos fundamentales: Los argumentos solo posicionales pueden usarse para los parámetros que son intrínsecos a la función y cuyo significado se entiende claramente por su posición (como el ID del producto y la cantidad en el ejemplo).
- Flexibilidad para argumentos contextuales: Los argumentos que pueden ser posicionales o de palabra clave ofrecen cierta flexibilidad en la llamada.
- Explicitación de opciones: Los argumentos solo de palabra clave obligan al usuario a ser explícito sobre el propósito de ciertos parámetros, especialmente las opciones booleanas o las configuraciones específicas.
Consideraciones al Diseñar Funciones:
- Piensa cuidadosamente sobre qué argumentos se benefician de ser solo posicionales, cuáles pueden ser flexibles y cuáles deben ser solo de palabra clave para la claridad.
- Una buena regla general es usar argumentos solo posicionales para los parámetros principales y obligatorios, argumentos solo de palabra clave para las opciones y configuraciones, y permitir la flexibilidad (posicional o de palabra clave) para los parámetros que se usan con frecuencia pero cuyo nombre podría mejorar la legibilidad en algunos casos.
Combinar argumentos solo posicionales y solo de palabra clave te permite diseñar interfaces de función muy precisas y expresivas, lo que puede mejorar significativamente la usabilidad y el mantenimiento de tu código.
Recursion
🔄 Recursión: La Función que se Llama a Sí Misma
La recursión es una técnica de programación donde una función se define en términos de sí misma. Esto significa que la función se llama a sí misma dentro de su propio cuerpo. Para que una función recursiva no se ejecute infinitamente, debe tener uno o más casos base, que son condiciones bajo las cuales la función deja de llamarse a sí misma.
¿Cómo Funciona la Recursión?
Cuando una función recursiva se llama, se crea un nuevo marco en la pila de llamadas. Si la función se llama a sí misma, otro marco se añade a la pila. Este proceso continúa hasta que se alcanza un caso base. Cuando se alcanza el caso base, la función comienza a retornar, y cada llamada anterior en la pila de llamadas continúa su ejecución, posiblemente utilizando el valor de retorno de la llamada recursiva.
Ejemplo Clásico: Cálculo del Factorial
El factorial de un número entero no negativo \(n\), denotado por \(n!\), se define recursivamente como:
- \(n! = n \times (n-1)!\) para \(n > 0\)
- \(0! = 1\) (caso base)
Aquí tienes una implementación en Python:
def factorial_recursivo(n):
"""Calcula el factorial de un número de forma recursiva."""
if n == 0:
return 1 # Caso base
else:
return n * factorial_recursivo(n - 1)
print(f"Factorial de 5: {factorial_recursivo(5)}")
# Llamadas recursivas para factorial(5):
# 5 * factorial(4)
# 5 * (4 * factorial(3))
# 5 * (4 * (3 * factorial(2)))
# 5 * (4 * (3 * (2 * factorial(1))))
# 5 * (4 * (3 * (2 * (1 * factorial(0)))))
# 5 * (4 * (3 * (2 * (1 * 1))))
# 5 * (4 * (3 * (2 * 1)))
# 5 * (4 * (3 * 2))
# 5 * (4 * 6)
# 5 * 24
# 120
Otro Ejemplo: Sucesión de Fibonacci
La sucesión de Fibonacci se define recursivamente como:
- \(F(0) = 0\) (caso base)
- \(F(1) = 1\) (caso base)
- \(F(n) = F(n-1) + F(n-2)\) para \(n > 1\)
Implementación en Python:
def fibonacci_recursivo(n):
"""Calcula el n-ésimo número de Fibonacci de forma recursiva."""
if n <= 1:
return n # Casos base
else:
return fibonacci_recursivo(n - 1) + fibonacci_recursivo(n - 2)
print(f"El 7mo número de Fibonacci es: {fibonacci_recursivo(7)}")
# Llamadas recursivas (¡muchas!)
Consideraciones al Usar Recursión:
- Caso base: Es crucial definir uno o más casos base que detengan
la
recursión. Sin un caso base adecuado, la función se llamará a sí misma
infinitamente, lo que llevará a un error de "desbordamiento de pila"
(
RecursionError
). - Eficiencia: Las soluciones recursivas pueden ser elegantes y fáciles de entender para ciertos problemas, pero a veces pueden ser menos eficientes que las soluciones iterativas (usando bucles) debido a la sobrecarga de las llamadas a funciones y la gestión de la pila. Por ejemplo, el cálculo recursivo de Fibonacci es notoriamente ineficiente debido a la repetición de cálculos.
- Profundidad de la recursión: Python tiene un límite en la profundidad de las llamadas recursivas para evitar el desbordamiento de pila. Este límite se puede consultar y modificar (aunque generalmente no se recomienda aumentar el límite predeterminado).
Cuándo Usar Recursión:
La recursión es apropiada cuando el problema tiene una estructura recursiva natural, es decir, el problema se puede dividir en subproblemas más pequeños que son instancias del mismo problema. Algunos ejemplos comunes incluyen:
- Recorrer estructuras de datos recursivas como árboles y grafos.
- Implementar algoritmos como búsqueda binaria y ordenamiento por mezcla (merge sort).
- Solucionar problemas matemáticos definidos recursivamente (como factorial y Fibonacci).
La recursión es una herramienta poderosa en la caja de herramientas de un programador, pero es importante entender sus implicaciones en términos de eficiencia y la necesidad de un caso base claro.
0 Comentarios
Si desea contactar comigo, lo puede hacer atravez deste formulario gracias