Fundamentos

Tutorial Fundamentos: Paso de parámetros

PseInt: Tutorial sobre diferencias clave entre pasar parámetros por valor y por referencia, con ejemplos en PseInt y Python. Mejora tu comprensión de funciones.

Aprende Fundamentos GRATIS y certifícate

Parámetros por valor vs. por referencia: diferencias y ejemplos

En la programación, el modo en que se pasan los parámetros a una función es fundamental para entender cómo se comportarán las variables dentro y fuera de dicha función. En PseInt, al igual que en otros lenguajes, existen dos formas principales de pasar parámetros: por valor y por referencia.

El paso de parámetros por valor significa que se envía una copia del valor del argumento a la función. De este modo, cualquier modificación que se realice sobre el parámetro dentro de la función no afectará al valor original fuera de ella.

Por otro lado, el paso de parámetros por referencia implica que se pasa una referencia al argumento original, es decir, se trabaja directamente con la variable. Así, cualquier cambio realizado sobre el parámetro dentro de la función afectará directamente al valor original.

Veamos un ejemplo práctico en PseInt para ilustrar estas diferencias.

Ejemplo de paso por valor en PseInt:

Proceso PasoPorValor
    Definir numero Como Entero
    numero <- 5
    Escribir "Antes de la función, numero = ", numero
    IncrementarPorValor(numero)
    Escribir "Después de la función, numero = ", numero
FinProceso

SubProceso IncrementarPorValor(valor)
    valor <- valor + 1
FinSubProceso

En este ejemplo, el subproceso IncrementarPorValor recibe una copia del valor de numero. Al incrementar valor en 1, solo se modifica la copia local, sin afectar el valor de numero en el ámbito principal.

Ejemplo equivalente en Python:

def incrementar_por_valor(valor):
    valor = valor + 1

numero = 5
print("Antes de la función, numero =", numero)
incrementar_por_valor(numero)
print("Después de la función, numero =", numero)

En Python, el comportamiento es similar para tipos inmutables como los enteros; el valor original de numero no cambia tras llamar a la función.

Ahora, veamos cómo funciona el paso por referencia en Python:

En Python, para simular el paso por referencia, podemos utilizar objetos mutables. Veamos un ejemplo con una lista:

def incrementar_por_referencia(valor):
    valor[0] = valor[0] + 1

numero = [5]
print("Antes de la función, numero =", numero[0])
incrementar_por_referencia(numero)
print("Después de la función, numero =", numero[0])

En este caso, numero es una lista con un solo elemento. Al pasarla a la función, las modificaciones afectan directamente al contenido de la lista original.

Es importante comprender estas diferencias para evitar errores lógicos en nuestros programas. En PseInt, debemos indicar explícitamente cuando un parámetro se pasa por referencia usando Referencias. Como regla general, utilizaremos el paso por valor cuando no sea necesario modificar el parámetro original, y el paso por referencia cuando sí deseamos que los cambios en la función afecten al argumento original.

Parámetros opcionales y predeterminados

En muchos lenguajes de programación, es posible definir funciones con parámetros opcionales que tienen valores predeterminados. Esto permite llamar a una función sin especificar todos los argumentos, utilizando valores por defecto cuando no se proporcionan ciertos parámetros. Aunque PseInt no soporta directamente esta funcionalidad, es posible simular parámetros opcionales mediante ciertas técnicas.

Una forma de implementar parámetros predeterminados en PseInt es asignando valores por defecto dentro de la función cuando los parámetros son vacíos o nulos. Veamos un ejemplo donde calculamos el precio final de un producto aplicando un descuento opcional.

Ejemplo en Python:

def calcular_precio(precio, descuento=0):
    return precio - (precio * descuento / 100)

precio_base = 100
print("Precio sin descuento:", calcular_precio(precio_base))
print("Precio con descuento del 10%:", calcular_precio(precio_base, 10))

En Python, podemos definir directamente el descuento con un valor predeterminado de 0 en la firma de la función. Esto simplifica el código y mejora su legibilidad.

Otra técnica en PseInt es utilizar valores especiales que indiquen la ausencia de un parámetro. Por ejemplo, podemos asignar el valor -1 como indicador de que el descuento no ha sido proporcionado.

Ejemplo alternativo en Python:

def calcular_precio(precio, descuento=0):
    return precio - (precio * descuento / 100)

print("Precio sin descuento:", calcular_precio(precio=100))
print("Precio con descuento del 20%:", calcular_precio(precio=100, descuento=20))

El uso de argumentos nombrados mejora la claridad y permite especificar solo los parámetros necesarios.

Aunque PseInt tiene limitaciones respecto a los parámetros opcionales, comprender estas estrategias nos permite escribir funciones más versátiles. Al aplicar valores predeterminados manualmente, logramos que nuestras funciones sean más flexibles y sencillas de utilizar en diferentes contextos.

Uso de estructuras complejas como parámetros (arrays, objetos)

Al desarrollar programas más avanzados, es común trabajar con estructuras de datos complejas como arrays y objetos. La capacidad de pasar estas estructuras como parámetros a funciones permite crear código más modular y reutilizable.

En PseInt, los arrays son estructuras que almacenan múltiples valores en una sola variable. Podemos pasar arrays completos a funciones para procesarlos de manera eficiente. Cuando se pasan arrays como parámetros, es importante comprender cómo se comportan en relación con el paso por valor y por referencia.

Ejemplo de paso de listas como parámetros en Python:

def calcular_promedio(arreglo):
    suma = 0
    for valor in arreglo:
        suma += valor
    return suma / len(arreglo)

notas = []
for i in range(5):
    nota = float(input(f"Ingrese la nota {i+1}: "))
    notas.append(nota)
promedio = calcular_promedio(notas)
print("El promedio es:", promedio)

En Python, las listas son objetos mutables que se pasan por referencia, lo que permite que las funciones accedan y modifiquen sus elementos.

Además de arrays, es posible trabajar con matrices (arrays multidimensionales). Veamos cómo pasar una matriz como parámetro:

Ejemplo de paso de una matriz en Python:

def imprimir_matriz(m):
    for fila in m:
        for elemento in fila:
            print(elemento, end=" ")
        print()

matriz = []
for i in range(1,4):
    fila = []
    for j in range(1,4):
        fila.append(i * j)
    matriz.append(fila)
imprimir_matriz(matriz)

Los registros en permiten agrupar diferentes tipos de datos bajo una misma estructura. Podemos definir un registro y pasarlo como parámetro a una función o subproceso.

Ejemplo de uso de diccionarios para simular registros en Python:

def mostrar_estudiante(est):
    print("Nombre:", est["nombre"])
    print("Edad:", est["edad"])
    print("Notas:")
    for i, nota in enumerate(est["notas"], start=1):
        print(f"Nota {i}: {nota}")

alumno = {
    "nombre": "María",
    "edad": 20,
    "notas": [8.5, 9.0, 7.5]
}

mostrar_estudiante(alumno)

En este caso, utilizamos un diccionario para almacenar los datos del estudiante y lo pasamos como parámetro a la función mostrar_estudiante.

Es fundamental recordar que al pasar estructuras complejas como parámetros, debemos considerar si necesitamos modificar los datos originales.

Mejores prácticas al diseñar interfaces de funciones

Al diseñar interfaces de funciones es crucial seguir ciertas prácticas que mejoran la legibilidad, mantenibilidad y robustez del código. Una interfaz bien diseñada facilita el entendimiento y uso de las funciones por parte de otros desarrolladores y de uno mismo en el futuro.

Una de las primeras consideraciones es elegir nombres claros y descriptivos para las funciones. El nombre de la función debe reflejar su propósito y la acción que realiza. Por ejemplo, en lugar de llamar a una función Calcular, es más informativo llamarla CalcularPromedio.

Es recomendable limitar el número de parámetros que recibe una función. Funciones con muchos parámetros pueden ser difíciles de manejar y propensas a errores. Si es necesario, agrupar parámetros relacionados en estructuras como registros.

Es importante mantener la coherencia en el orden y tipo de los parámetros. Si varias funciones están relacionadas, seguir un patrón consistente facilita su uso. Por ejemplo, si todas las funciones que operan sobre una lista reciben primero la lista y luego otros parámetros, el usuario podrá recordarlas y usarlas con mayor facilidad.

Evitar los efectos secundarios es otra buena práctica. Una función debe limitarse a su tarea específica sin alterar el estado de variables globales o externas. Esto aumenta la confiabilidad y predecibilidad del código. Si es necesario modificar una variable global, es preferible pasarla como parámetro y documentar este comportamiento.

La documentación clara y concisa dentro del código es esencial. Incluir comentarios que expliquen el propósito de la función, describan los parámetros y especifiquen los valores de retorno. Por ejemplo:

// Función que calcula el factorial de un número entero positivo.
// Parámetros:
//   n: Entero positivo del cual se calculará el factorial.
// Retorna:
//   Entero que representa el factorial de n.
Funcion CalcularFactorial(n Como Entero) Como Entero
    Si n = 0 Entonces
        CalcularFactorial <- 1
    Sino
        CalcularFactorial <- n * CalcularFactorial(n - 1)
    FinSi
FinFuncion

En Python, la documentación se puede añadir usando docstrings:

def calcular_factorial(n):
    """
    Calcula el factorial de un número entero positivo.

    Parámetros:
        n (int): Entero positivo del cual se calculará el factorial.

    Retorna:
        int: Factorial de n.
    """
    if n == 0:
        return 1
    else:
        return n * calcular_factorial(n - 1)

Implementar manejo de errores adecuado dentro de las funciones mejora la robustez del programa. Es preferible verificar las precondiciones y validar los parámetros al inicio de la función. 

Al diseñar interfaces, es útil considerar la extensibilidad y flexibilidad de las funciones. Permitir que soporten diferentes escenarios sin modificar su implementación interna. Esto se puede lograr mediante parámetros predeterminados o aceptando diferentes tipos de datos cuando tenga sentido.

Mantener las funciones enfocadas en una sola responsabilidad, siguiendo el principio de responsabilidad única, facilita su comprensión y reutilización. Si una función está realizando múltiples tareas, puede ser conveniente dividirla en funciones más pequeñas.

Por último, evitar el uso de valores mágicos o números sin explicación en el código. Es preferible definir constantes con nombres significativos. Por ejemplo:

En Python:

TASA_IVA = 0.21

def calcular_precio_final(precio_base):
    precio_final = precio_base * (1 + TASA_IVA)
    return precio_final

Siguiendo estas mejores prácticas, se crea código más legible, mantenible y menos propenso a errores. Una interfaz de función bien diseñada es fundamental para desarrollar programas eficientes y escalables. Al invertir tiempo en planificar y estructurar adecuadamente las funciones, se facilita el proceso de programación y se mejora la calidad del software.

Para seguir leyendo hazte Plus

¿Ya eres Plus? Accede a la app

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende Fundamentos GRATIS online

Todas las lecciones de Fundamentos

Accede a todas las lecciones de Fundamentos y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Fundamentos y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Entender cómo se pasan los parámetros por valor y referencia.
  • Aprender a implementar ejemplos prácticos en PseInt y Python.
  • Comparar el comportamiento de parámetros en PseInt y Python.
  • Aprender técnicas para simular parámetros opcionales y predeterminados en PseInt.
  • Manejar estructuras complejas como arrays y objetos al pasar parámetros.
  • Adoptar mejores prácticas al diseñar interfaces de funciones.