Argumentos por posiciones y nombre



@eduardo_gpg

Número de visitas 3133

Tiempo de lectura 5 min

21 Octubre 2021

Algo que sin duda me gusta muchísimo de Python es el tema de funciones. Y ya lo he dicho en entregas anteriores, en Python las funciones por sí solas se merecen un libro completo. 😵

Y no exagero, son demasiados los conceptos que podemos abordar con el tema de funciones, por ejemplo closures, decoradores, scopes, variables locales, globales, lambdas etc...

Sin dejar a un lado que a partir de las funciones podemos pasar de la programación estructurada a la programación orientada a objetos, funcional, concurrente etc ...

Es por ello que en esta ocasión me gustaría mostrarte un par de features incorporadas al lenguaje que nos permitirán crear funciones aun más flexibles, robustas, reutilizables y sobre todo, fáciles de mantener.

Así que, sin más introducción, comencemos con este post. 🍻

Argumentos y parámetros.

Lo primero que debemos tener en claro, antes de entrar de lleno con los temas principales, es saber la diferencias entre argumentos y parámetros. Recordando que un argumento no será más que el valor que vamos a ingresar al momento de llamar a una función, y los parámetros serán variables definidas en la función misma que podrán almacenar los argumentos ingresados.

Veamos un ejemplo para recordar.

def suma(a, b, c):
    return a + b + c

En este caso hemos definido la función suma. Función que posee 3 parámetros (a, b y c).

Estos parámetros no poseen valores por default, esto quiere decir que al hacer el llamado a la función, será necesario definir sus valores. Y para ello la forma más sencilla es utilizar argumentos.

Simplemente, al hacer el llamado a la función, colocamos los argumentos. En este caso 3.

Ejemplos.

# Argumentos por posición
suma(10, 20, 30)
60

En Python la asignación de argumentos se realiza por posición, esto quiere decir que el primer argumento es asignado al primer parámetro, el segundo argumento al segundo parámetro y así sucesivamente. A esta asignación la conoceremos como positional argument. Y será la forma más común de llamar a una función.

Ok, hasta aquí todo bien con los argumentos y los parámetros. Sin embargo déjame decirte que en Python existe otra forma en la cual podemos llamar a una función, y esta vez lo haremos utilizando el nombre de los parámetros.

Veamos.

suma(b=10, c=20, a=30)
60

En este caso, como podemos observar, asignamos valores ya no por posición, si no por nombre.

Lo interesante de la asignación por nombre, es que el orden no importa; solo basta con colocar el nombre del parámetro (Al cual queremos hacer la asignación), signo igual (=) y su correspondiente valor. A esta asignación la conoceremos como keyword argument. 🕵️‍♀️

NOTA: Una muy buena práctica en Python, es realizar la asignación por nombre sin espacio. variable=valor.

La asignación por nombre lo podemos hacer en prácticamente cualquier versión de Python 2.x o 3.x. Lo interesante ocurren en versiones actuales del lenguaje, donde es posible definir que valores podrán ser asignados por posición o por nombre.

Keyword only

Listo, los conceptos básicos ya los tenemos, ahora modifiquemos un poco el ejemplo, y trabajemos con solo argumentos por posición.

def suma(a, *, b, c):
    return a + b + c

En este caso hemos añadido el asterisco (*) en la sección de parámetros, pero ¿Qué significa esto? Verás, al hacer esto, le indicamos a Python que todos los parámetros que se encuentren a la derecha del asterisco únicamente podrán tomar su valor por nombre y no por posición.

Si intento ejecutar la función utilizando únicamente positional arguments obtendremos un error. 🤯

>>> suma(10, 20, 30)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: suma() takes 1 positional argument but 3 were given

El error es bastante claro, la función solo puede recibir un argumento por posición (que sería para el parámetro a) pero estamos pasando 3.

Lo quedemos hacer para evitar el error, es simplemente asignar los valores por keyword arguments.

>>> suma(10, b=20, c=30)
60

Ahora sí, obtendremos el resultado deseado, sin ningún error.

Y ¿Qué pasa si intentamos asignar un valor directamente para el parámetro a?

>>> suma(a=10, b=20, c=30)
60

Bueno, no pasa absolutamente nada.

A los parámetros que se encuentren a la izquierda del asterisco (*) se les puede asignar su valor ya sea por posición o por nombre. 🥳

El uso del asterisco (*) nos permite un mayor control sobre la asignación o modificación de valores para los parámetros. Por ejemplo, que pasa si tenemos un parámetro que tiene un valor por default, pero solo queremos que dicho valor sea modificado cuando el usuario lo haga de forma explícita, es decir, directamente por su nombre.

En esos casos lo mejor que podemos hacer es utilizar el Keyword only. Veamos.

def database_connection(username, password, host, *, port=3306):
    pass

En este caso donde la función posee 4 parámetros, pero solo quiero que 3 de ellos puedan ser asignados por posición o nombre, hacemos uso del asterisco. Con lo cual, si el usuario quiere utilizar un puerto diferente al default, debe hacerlo de forma explícita, reduciendo la posibilidad de error.

database_connection('eduardo_gpg', 'password123', 'localhost', port=29017)

Cool.

Positional only

Continuando con el post,algo que me gustaría mencionar es que, a partir de la versión 3.8 de Python, es posible la asignación de valores solo por posición, es decir, lo contrario de lo que acabamos de ver. Y para ello haremos uso del slash (/). 🐍

def suma(a, b,  /, c):
    return a + b + c

Para este nuevo ejemplo, le indicamos a Python que todos los parámetro que se encuentren a la izquierda del slash , solo podrán tomar su valor por posición y no por nombre.

Si por ejemplo intento ejecutar asignando nombres, obtendré un error.

>>> suma(a=10, b=20, c=30)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: suma() got some positional-only arguments passed as keyword arguments: 'a, b'

De igual forma, el error es bastante claro. No es posible utilizar argumentos por nombre para a y b.

Lo correcto sería hacerlo todo por posición. 🥂

>>> suma(10, 20, 30)
60

Lo interesante de todo esto es que, al limitar argumentos solo por posición, en caso deseemos modificar la definición de la función, por ejemplo que ahora los parámetros cambien sus nombre (n1, n2 y n3) este cambio no debiera repercutir de ninguna forma a las implementaciones de la función, ya que la asignación siempre se hizo por posición y nunca por nombre, por lo tanto sería un cambio completamente transparente para el usuario.

Keyword only & Positional only

Ya para finalizar me gustaría mencionar que sí, es posible hacer uso de los keyword only y positional only en una misma función. Que si bien, nunca he tenido la necesidad de hacerlo, y siendo sinceros no se me ocurre un escenario para ello. Spi es posible. 🤯

Aquí un pequeño ejemplo.

def function(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
            -----------    ----------     ----------
                |             |                  |
                |        Positional or keyword   |
                |                                - Keyword only
                -- Positional only

Espero que puedas encontrar un caso práctico para la implementación, y sí es así, no olvides compartirlo en la sección de comentarios. 🤠


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍