El conocimiento es el nuevo dinero.
Aprender es la nueva manera en la que inviertes
Acceso Cursos

Todo * se puede utilizar en Python (aparte de las matemáticas básicas)

· 8 min de lectura
Todo * se puede utilizar en Python (aparte de las matemáticas básicas)

En Python, el operador * no se limita a multiplicaciones o potencias. Este pequeño símbolo es mucho más poderoso y versátil de lo que parece, ofreciendo funcionalidades avanzadas en diversos contextos:

  • Argumentos variables: Puedes usar *args en funciones para aceptar una cantidad ilimitada de argumentos posicionales.
  • Desempaquetado de listas y tuplas: El operador * permite expandir estructuras iterables, facilitando la combinación o separación de elementos.
  • Asignación múltiple: Con *, es posible capturar múltiples elementos restantes de una lista en una sola variable.
  • Separación de argumentos posicionales y nombrados: En funciones, * puede actuar como separador entre los dos tipos de argumentos, mejorando la legibilidad y control de llamadas complejas.
CPU
1 vCPU
MEMORIA
1 GB
ALMACENAMIENTO
10 GB
TRANSFERENCIA
1 TB
PRECIO
$ 4 mes
Para obtener el servidor GRATIS debes de escribir el cupon "LEIFER"

Este operador es una herramienta fundamental para escribir código más limpio, flexible y potente en Python.

# 1. Usando *args para argumentos variables en una función
def func(*args):
    print(args)

func(1, 2, 3)  # Salida: (1, 2, 3)


# 2. Desempaquetado de listas o tuplas
a = [1, 2]
b = [3, 4]

print(*a, *b)  # Salida: 1 2 3 4


# 3. Desempaquetado con variables y el operador *
ls = [1, 2, 3, 4, 5]
a, b, *others = ls

print(a, b)       # Salida: 1 2
print(others)     # Salida: [3, 4, 5]


# 4. Separación de argumentos posicionales y con nombre en una función
def func(a, b, *, c, d):
    print(a, b, c, d)

# Llamadas de función
func(1, 2, c=3, d=4)  # OK
func(1, 2, 3, 4)      # Error: no es posible

*args en los parámetros de función

Podemos añadir *args en nuestros parámetros de función para permitir que nuestra función acepte cualquier número de argumentos posicionales.

def hello(*args):
    print(args)

hello()              # ()
hello(1)             # (1,)
hello(1, 2)          # (1, 2)
hello(1, 2, 3, 4)    # (1, 2, 3, 4)

^ Observa que nuestra función hello toma *args: podemos pasar cualquier número de argumentos a hello, y todos ellos quedarán atrapados en una tupla llamada args.

Ten en cuenta que podemos reemplazar el nombre de variable args por cualquier nombre de variable válido, pero el * tiene que estar ahí:

def hello(*stuff):
    print(stuff)

hello()              # ()
hello(1)             # (1,)
hello(1, 2)          # (1, 2)
hello(1, 2, 3, 4)    # (1, 2, 3, 4)

Si combinamos esto con parámetros normales, por ejemplo a & b, los parámetros normales se rellenarán primero, mientras que args tomará el resto de los argumentos sin rellenar.

def hi(a, b, *args):
    print(f"{a=} {b=} {args=}")

hi()                 # error
hi(1)                # error
hi(1, 2)             # a=1 b=2 args=()
hi(1, 2, 3, 4)       # a=1 b=2 args=(3, 4)

^ aquí, si no pasamos nada a a o b, obtenemos errores como los de los dos primeros ejemplos. args captura todos los demás argumentos posicionales distintos de a y b.

**kwargs en parámetros de función

Si usamos ** en lugar de *, hacemos lo mismo con los argumentos de palabra clave: añadir **kwargs a nuestra función le permite aceptar cualquier número de argumentos de palabra clave.

Nota: si no está familiarizado, los argumentos de palabra clave se refieren a los argumentos que pasamos usando un formato varname=value, como los que se muestran a continuación.

def hi(**kwargs):
    print(kwargs)

hi()                       # {}
hi(a=1)                    # {'a': 1}
hi(a=1, b=2)               # {'a': 1, 'b': 2}
hi(a=1, b=2, c=3)          # {'a': 1, 'b': 2, 'c': 3}

^ todos los argumentos de palabra clave adicionales se recogerán en un diccionario llamado kwargs.

Una vez más, no tenemos que usar el nombre kwargs si no queremos, aunque yo uso el nombre kwargs por defecto debido a la convención. Sin embargo, el ** tiene que estar ahí.

def hi(**things):
    print(things)

hi()                       # {}
hi(a=1)                    # {'a': 1}
hi(a=1, b=2)               # {'a': 1, 'b': 2}
hi(a=1, b=2, c=3)          # {'a': 1, 'b': 2, 'c': 3}

Del mismo modo, podemos combinarlos con parámetros normales, pero debemos asegurarnos de pasar primero algo a los parámetros normales. kwargs almacena todos los demás argumentos de palabra clave no utilizados en un diccionario.

def hi(a, b, **kwargs):
    print(f"{a=} {b=} {kwargs=}")

hi()                          # error
hi(a=1)                       # error
hi(a=1, b=2)                  # a=1 b=2 kwargs={}
hi(a=1, b=2, c=3)             # a=1 b=2 kwargs={'c': 3}
hi(a=1, b=2, c=3, d=4)        # a=1 b=2 kwargs={'c': 3, 'd': 4}

^ si no pasamos nada a a o b, obtenemos errores, al igual que en los dos primeros ejemplos

*args en argumentos de función

También podemos usar * fuera de las funciones. Más concretamente, podemos usar * para desempaquetar nuestro iterable (piense en lista, tupla, etc.) en los argumentos de nuestra función.
Aquí tenemos una función simple hi(a, b, c)

def hi(a, b, c):
    print(f"{a=} {b=} {c=}")

hi(1, 2, 3)                 # a=1 b=2 c=3

mylist = [4, 5, 6]
hi(*mylist)                 # a=4 b=5 c=6

podemos llamarlo normalmente usando hi(1, 2, 3)

también podemos pasar una lista de longitud 3 (mylist) con un * delante — hi(*mylist) es lo mismo que hi(4, 5, 6)

Dado que hi(a, b, c) requiere que se le pasen exactamente 3 argumentos, tenemos la libertad de pasar 1 argumento posicional junto con *[5, 6], ya que esto hace 3; solo tenemos que asegurarnos de que se pase el número correcto de argumentos.

def hi(a, b, c):
    print(f"{a=} {b=} {c=}")

mylist = [4, 5, 6]
hi(*mylist)                 # a=4 b=5 c=6

mylist = [5, 6]
hi(4, *mylist)              # a=4 b=5 c=6

mylist = [4, 5, 6, 7, 8]
hi(*mylist)                 # error

**kwargs en los argumentos de función

Y si usamos ** en lugar de *, podemos hacer lo mismo con los diccionarios.

Aquí, hi(**mydict) es lo mismo que hi(a=4, b=5, c=6)

def hi(a, b, c):
    print(f"{a=} {b=} {c=}")

hi(a=4, b=5, c=6)           # a=4 b=5 c=6

mydict = {"a": 4, "b": 5, "c": 6}
hi(**mydict)                # a=4 b=5 c=6

De manera similar, también podemos combinar argumentos de palabra clave normales con **mydict siempre que pasemos todos los argumentos de palabra clave requeridos a nuestra función.

def hi(a, b, c):
    print(f"{a=} {b=} {c=}")

mydict = {"a": 4, "b": 5, "c": 6}
hi(**mydict)                # a=4 b=5 c=6

mydict = {"b": 5, "c": 6}
hi(a=4, **mydict)           # a=4 b=5 c=6

Cualquier parámetro después de * debe ser un argumento de palabra clave.

Definamos una función con * sola

def hello(a, b, *, c, d):
    # c and d MUST be keyword arguments
    print(a, b, c, d)

hello(1, 2, c=3, d=4)         # 1 2 3 4
hello(a=1, b=2, c=3, d=4)     # 1 2 3 4
hello(1, 2, 3, 4)             # error

^ esta vez, * no se coloca antes de ningún parámetro, lo que significa que cualquier parámetro definido después de * debe ser un argumento de palabra clave.

En este caso, c y d van después de *, por lo que c y d solo pueden ser argumentos de palabra clave: a Python no le importa si pasamos argumentos posicionales o de palabra clave en a y b, pero c y d deben ser argumentos de palabra clave (o de lo contrario se genera un error).

Por el contrario, si reemplazamos * solo por / solo, esto significa que cualquier parámetro de función definido antes de / debe ser un argumento posicional.

def hello(a, b, *, c, d):
    # c and d MUST be keyword arguments
    print(a, b, c, d)

hello(1, 2, c=3, d=4)         # 1 2 3 4
hello(a=1, b=2, c=3, d=4)     # 1 2 3 4
hello(1, 2, 3, 4)             # error

Podemos combinarlos para imponer restricciones adicionales en nuestros parámetros de función.

def hola(a, b, /, c, d, *, e, f):
    # a and b must be positional arguments
    # c and d can be either
    # e and f must be keyword arguments
    print(a, b, c, d, e, f)

*args en el desempaquetado de tuplas

En Python, podemos utilizar el desempaquetado de tuplas para asignar elegantemente múltiples variables a la vez.

person = ["bob", "m", 20]

name, gender, age = person

print(name)       # bob
print(gender)     # m
print(age)        # 20

Podemos combinar el desempaquetado de tuplas con * si tenemos variables sin usar.

Digamos que tenemos muchos más campos en persona, pero solo necesitamos los dos primeros por ahora; podemos usar *others para asignar todo lo demás a la variable others.

person = ["bob", "m", 20, 1.75, 70, "black"]

name, gender, *others = person

print(name)       # bob
print(gender)     # m
print(others)     # [20, 1.75, 70, 'black']

También podemos cambiar la posición de la variable con *: en este ejemplo, solo necesitamos el primer y el último valor, así que ponemos *others en el medio.

person = ["bob", "m", 20, 1.75, 70, "black"]

name, *others, hair = person

print(name)       # bob
print(hair)       # black
print(others)     # ['m', 20, 1.75, 70]

Y en este ejemplo, solo necesitamos los 2 últimos valores, así que podemos poner *otros al principio.

person = ["bob", "m", 20, 1.75, 70, "black"]

*others, weight, hair = person

print(weight)     # 70
print(hair)       # black
print(others)     # ['bob', 'm', 20, 1.75]

Uso de * al combinar iterables

También podemos usar * para combinar iterables como listas, tuplas, conjuntos, etc.

Aquí, combinamos 2 listas a y b desempaquetándolas en otra lista c

a = [1, 2]
b = [3, 4]
c = [-1, 0, *a, *b, 5, 6]

print(c)       # [-1, 0, 1, 2, 3, 4, 5, 6]

Nota: esto también funciona para otros iterables como conjuntos y tuplas.

** en la combinación de diccionarios

De manera similar, ** funciona para las asignaciones de clave-valor de la misma manera que * funciona para valores individuales. Podemos usar ** para desempaquetar diccionarios en otros diccionarios para combinarlos.

x = {"a": 1, "b": 2}
y = {"c": 3, "d": 4}

z = {**x, **y}
print(z)       # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

También podemos combinar esta técnica con pares clave-valor normales al crear nuestro diccionario combinado.

x = {"a": 1, "b": 2}
y = {"c": 3, "d": 4}

z = {**x, **y, "e": 5}
print(z)       # {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Importar todo desde un módulo

También podemos usar desde modulename import * para decirle a Python que queremos importar todo lo que se puede importar desde algún módulo.

from colorama import *
# importing everything from 'colorama' module


Conclusión

¡Espero que hayas aprendido algo nuevo hoy!

Fuente