miércoles, 22 de mayo de 2024

Lenguajes. Python

Colecciones como parámetros

Para finalizar con el tema de los parámetros/argumentos de una función, trataremos en esta entrada sobre parámetros basados en colecciones de datos.


De hecho, hasta ahora hemos estado tratando los parámetros como variables o, a lo sumo, como elementos de un diccionario (por eso de palabra clave = valor), pero no hemos contemplado la posibilidad pasar un número variable de elementos, esto es: un número de elementos no predefinidos a priori. Para hacer esto podemos definir parámetros mediante fórmulas específicas: *args y **kwargs.

Los parámetros basados en colecciones permiten, por la propia condición de las colecciones de datos, hacer variable el número efectivo de datos que se pasa a la función como argumento en el momento en que es llamada.

Para identificar este tipo de parámetros, en realidad lo distintivo son los asteriscos que preceden al nombre, siendo arg (arguments)kwargs (keyword arguments) identificadores convencionales. Lo que diferencia *args de **kwargs, es que un asterisco (*) indica que estamos empleando una lista como parámetro/argumento y dos asteriscos (**) que estamos utilizando un diccionario (keyword=value). Pero ambos tienen una utilidad básica común: hacer variable y flexible el número se elementos que se pasa como argumentos a una función (1).

El uso de ambas colecciones como argumentos no supone mayor diferencia respecto al uso de variables: simplemente se separa cada argumento por una coma, aunque cuando empleamos **kwargs debemos utilizar la fórmula clave=valor.

Aunque es posible utilizar los tres tipos de componentes (variables, listas y diccionarios) a la hora de establecer los parámetros de una función, pudiendo además estar situados de cualquier posición, cuando pasamos los argumentos que se asocian a estos parámetros es necesario emplear la fórmula clave=valor (argumentos nombrados) a partir del argumento que se asocia con una colección de datos (esto es, con *args o con **kwargs), ya que, en caso contrario, pueden darse interpretaciones erróneas en la asociación parámetro-argumento. Tal sería el siguiente caso en el que definimos la función func_prueba1() con los siguientes parámetros:

def func_prueba1(a,b,*args,c)

Al pasar argumentos desde la llamada a la función...

func_prueba1(4,5,7,9,8)

... el último elemento (8) es interpretado como perteneciente/asociado al parámetro c, dando error por no estar identificado mediante keyword (palabra clave). Así que o lo identificamos convenientemente...

 func_prueba1(4,5,7,9,c=8)

... o asignamos 8 a *args y reorganizamos el posicionamiento de c en el listado de parámetros o asignamos un valor 0 a c, mientras mantenemos 8 como argumento perteneciente a *args.

                     func_prueba1(4,5,7,9,8,c='')

Además de los parámetros anteriores, también podemos utilizar colecciones de datos asignándolas a variables que, a su vez, utilizamos como argumentos. En este caso, lo que hacemos es pasar como argumento el conjunto de componentes de la colección (por ejemplo una lista, como en este script). Si observamos la salida de la función comprobaremos que efectivamente hemos pasado una colección de datos:

                    [2, 4, 6, 8] -> que implica que se trata de una lista
  4                -> que implica que funciona la built-in function len(), apropiada para el
                       tratamiento de listas 
 
Es más, si hubiéramos definido el argumento como *args, lo que obtendríamos como salida de la función...

([2, 4, 6, 8],)
1

... nos indica que Python está identificando el conjunto [2, 4, 6, 8] como una lista, pero también que entiende el conjunto de potenciales parámetros como una colección, por lo que este elemento es a la vez un elemento de esa colección de orden superior; un elemento identificado como lista, pero un único elemento, por eso cuando aplicamos la función len() nos devuelve 1 como resultado, no 4 como en el caso anterior.

Debemos tener en cuenta esta diferencia en el tratamiento de los parámetros empleados como colecciones de datos para saber cómo procesarlos mediante una función. Un segundo ejemplo de la importancia de lo anterior: si deseáramos que la función nos devolviera el elemento 0 de la lista pasada como argumento (print(a[0])), en caso de emplear la fórmula *args, ese primer elemento sería la propia lista, por lo que me devolvería [2, 4, 6, 8], mientras que si el argumento es tratado como variable, el resultado sería 2. Las implicaciones de todo esto son obvias.

NOTA

(1) Recuerda que una lista es una colección de datos de diferente tipo, ordenada, modificable que permite datos repetidos y se identifica por ir entre []. Un diccionario, por el contrario, es una colección de datos no ordenada, indexada (keyword = valor), modificable, que no admite datos duplicados y que se identifica por ir entre {}.

No hay comentarios:

Publicar un comentario

Comenta esta entrada