Coincidencia de patrones estructurales en Python
- Introducción a la coincidencia de patrones estructurales y su importancia
- Utilice la coincidencia de patrones estructurales en Python
Antes de Python 3.10, no teníamos ninguna forma integrada de usar la coincidencia de patrones estructurales, lo que se conoce como cambio de caso
en otros lenguajes de programación. A partir del lanzamiento de Python 3.10, no podemos usar la declaración match ... case
para emular la declaración switch-case
.
Este tutorial presenta la coincidencia de patrones estructurales y su importancia en Python. También utiliza diferentes patrones para demostrar el uso de la declaración match ... case
.
Introducción a la coincidencia de patrones estructurales y su importancia
A partir de los primeros días de 2021, no pudimos usar la palabra clave coincidir
en las versiones publicadas de Python que son inferiores o iguales a 3.9. En ese momento, estábamos acostumbrados a simular cambiar... caso
usando un diccionario o sentencias if/elif/else
anidadas.
Pero, Python 3.10 ha introducido una nueva función conocida como coincidencia de patrones estructurales (declaración match ... case
). Es equivalente a una declaración de cambiar... caso
como la que tenemos en Java, C++ y muchos otros lenguajes de programación.
Esta nueva característica nos ha permitido escribir declaraciones de control de flujo de errores simples, fáciles de leer y con una probabilidad mínima de error.
Utilice la coincidencia de patrones estructurales en Python
La coincidencia de patrones estructurales se usa como una declaración de cambio de caso
y es más poderosa que esto. ¿Cómo? Exploremos algunos ejemplos a continuación para aprender sus usos en diferentes situaciones.
Uso básico de la sentencia match ... case
Código de ejemplo:
# >= Python 3.10
colour = "blue"
match colour:
case "green":
print("The specified colour is green")
case "white":
print("Wow, you've picked white")
case "green":
print("Great, you are going with green colour")
case "blue":
print("Blue like sky...")
Producción :
Blue like sky...
Aquí, primero tenemos una variable color
que contiene azul
. Luego, usamos la palabra clave match
, que hace coincidir el valor de la variable color
con varios casos específicos donde cada caso comienza con la palabra clave case
seguida de un patrón que queremos comparar o verificar.
El patrón puede ser uno de los siguientes:
- patrón literal
- patrón de captura
- patrón comodín
- patrón de valor constante
- patrón de secuencia
- patrón de mapeo
- patrón de clase
- O patrón
- patrón de morsa
La instrucción coincidir... caso
solo ejecuta el código bajo el primer caso
que coincidió.
¿Qué pasa si ningún caso
coincide? ¿Cómo se enterará el usuario? Para eso, podemos tener un caso
predeterminado de la siguiente manera.
Código de ejemplo:
# >= Python 3.10
colour = "yellow"
match colour:
case "green":
print("The specified colour is green")
case "white":
print("Wow, you've picked white")
case "green":
print("Great, you are going with green colour")
case "blue":
print("Blue like sky...")
case other:
print("No match found!")
Producción :
No match found!
Utilice match ... case
para detectar y deconstruir estructuras de datos
Código de ejemplo:
# >= Python 3.10
student = {"name": {"first": "Mehvish", "last": "Ashiq"}, "section": "B"}
match student:
case {"name": {"first": firstname}}:
print(firstname)
Producción :
Mehvish
En el ejemplo anterior, la coincidencia de patrones estructurales está en acción en las siguientes dos líneas de código:
# >= Python 3.10
match student:
case {"name": {"first": firstname}}:
Usamos la instrucción match ... case
para encontrar el nombre del estudiante extrayéndolo de la estructura de datos student
. Aquí, el estudiante
es un diccionario que contiene la información del estudiante.
La línea caso
especifica nuestro patrón para que coincida con el estudiante
. Teniendo en cuenta el ejemplo anterior, buscamos un diccionario con la clave el "nombre"
cuyo valor es un nuevo diccionario.
Este diccionario anidado contiene una clave "first"
cuyo valor está vinculado a la variable firstname
. Finalmente, usamos la variable firstname
para imprimir el valor.
Hemos aprendido el patrón de mapeo aquí si lo observa más profundamente. ¿Cómo? El patrón de mapeo se parece a {"student": s, "emails": [*es]}
, que coincide con el mapeo con al menos un conjunto de claves específicas.
Si todos los subpatrones coinciden con sus valores correspondientes, vincula cualquier vínculo de subpatrón durante la coincidencia con los valores correspondientes a las claves. Si queremos permitir la captura de elementos adicionales, podemos agregar **rest
al final del patrón.
Utilice match ... case
con el patrón de captura y el patrón de secuencia
Código de ejemplo:
# >= Python 3.10
def sum_list_of_numbers(numbers):
match numbers:
case []:
return 0
case [first, *rest]:
return first + sum_list_of_numbers(rest)
sum_list_of_numbers([1, 2, 3, 4])
Producción :
10
Aquí, usamos la función recursiva para usar el patrón de captura para capturar la coincidencia con el patrón especificado y vincularlo al nombre.
En este ejemplo de código, el primer caso
devuelve 0
como suma si coincide con una lista vacía. El segundo caso
utiliza el patrón de secuencia con dos patrones de captura para hacer coincidir las listas con uno de varios elementos/elementos.
Aquí, el primer elemento de una lista se captura y vincula al “primer” nombre, mientras que el segundo patrón de captura, *rest
, usa la sintaxis de desempaquetado para hacer coincidir cualquier número de elementos/elementos.
Tenga en cuenta que el resto
se une a la lista que tiene todos los elementos/elementos de números, excluyendo el primero. Para obtener el resultado, llamamos a la función sum_list_of_numbers()
pasando una lista de números como se indicó anteriormente.
Utilice match ... case
con el patrón comodín
Código de ejemplo:
# >= Python 3.10
def sum_list_of_numbers(numbers):
match numbers:
case []:
return 0
case [first, *rest]:
return first + sum_list_of_numbers(rest)
case _:
incorrect_type = numbers.__class__.__name__
raise ValueError(
f"Incorrect Values. We Can only Add lists of numbers,not {incorrect_type!r}"
)
sum_list_of_numbers({"1": "2", "3": "4"})
Producción :
ValueError: Incorrect Values. We Can only Add lists of numbers, not 'dict'
Hemos aprendido el concepto de usar el patrón comodín mientras aprendimos el uso básico de la instrucción coincidir ... caso
, pero no introdujimos el término patrón comodín allí. Imagine un escenario en el que los dos primeros casos no coinciden y necesitamos tener un patrón general como nuestro caso
final.
Por ejemplo, queremos generar un error si obtenemos cualquier otro tipo de estructura de datos en lugar de una lista. Aquí, podemos usar _
como un patrón comodín, que coincidirá con cualquier cosa sin vincularse al nombre. Agregamos manejo de errores en este caso
final para informar al usuario.
¿Qué dices? ¿Es bueno ir con nuestro patrón? Vamos a probarlo llamando a la función sum_list_of_numbers()
pasando una lista de valores de cadena de la siguiente manera:
sum_list_of_numbers(["1", "2", "3", "4"])
Producirá el siguiente error:
TypeError: can only concatenate str (not "int") to str
Entonces, podemos decir que el patrón aún no es lo suficientemente infalible. ¿Por qué? Porque pasamos la estructura de datos de tipo lista a la función sum_list_of_numbers()
pero tenemos valores de tipo cadena, no de tipo int como esperábamos.
Consulte la siguiente sección para saber cómo resolverlo.
Usa match ... case
con el patrón de clase
Código de ejemplo:
# >= Python 3.10
def sum_list_of_numbers(numbers):
match numbers:
case []:
return 0
case [int(first), *rest]:
return first + sum_list_of_numbers(rest)
case _:
raise ValueError(f"Incorrect values! We can only add lists of numbers")
sum_list_of_numbers(["1", "2", "3", "4"])
Producción :
ValueError: Incorrect values! We can only add lists of numbers
El caso base (el primer caso
) devuelve 0
; por lo tanto, sumar solo funciona para los tipos que podemos sumar con números. Tenga en cuenta que Python no sabe cómo agregar cadenas de texto y números.
Entonces, podemos usar el patrón de clase para restringir nuestro patrón para que solo coincida con números enteros. El patrón de clase es similar al patrón de mapeo pero coincide con los atributos en lugar de las claves.
Usa match ... case
con el patrón OR
Código de ejemplo:
# >= Python 3.10
def sum_list_of_numbers(numbers):
match numbers:
case []:
return 0
case [int(first) | float(first), *rest]:
return first + sum_list_of_numbers(rest)
case _:
raise ValueError(f"Incorrect values! We can only add lists of numbers")
Supongamos que queremos hacer que la función sum_list_of_numbers()
funcione para una lista de valores, ya sean valores de tipo int o de tipo flotante. Usamos el patrón OR representado con un signo de tubería (|
).
El código anterior debe generar el ValueError
si la lista especificada contiene valores que no sean valores de tipo int o float. Probemos considerando los tres escenarios a continuación.
Prueba 1: pase una lista que tenga valores de tipo int:
sum_list_of_numbers([1, 2, 3, 4]) # output is 10
Prueba 2: Pase una lista que tenga valores de tipo flotante:
sum_list_of_numbers([1.0, 2.0, 3.0, 4.0]) # output is 10.0
Prueba 3: pase una lista que tenga cualquier otro tipo, excepto los tipos int y float:
sum_list_of_numbers(["1", "2", "3", "4"])
# output is ValueError: Incorrect values! We can only add lists of numbers
Como puede ver, la función sum_list_of_numbers()
funciona tanto para valores de tipo int como float debido al uso del patrón OR.
Usa match ... case
con el Patrón Literal
Código de ejemplo:
# >= Python 3.10
def say_hello(name):
match name:
case "Mehvish":
print(f"Hi, {name}!")
case _:
print("Howdy, stranger!")
say_hello("Mehvish")
Producción :
Hi, Mehvish!
Este ejemplo usa un patrón literal que coincide con el objeto literal, por ejemplo, un número explícito o una cadena, como ya hicimos mientras aprendíamos el uso básico de la instrucción match ... case
.
Es el tipo de patrón más básico y nos permite simular una instrucción switch ... case
similar a Java, C++ y otros lenguajes de programación. Puede visitar esta página para conocer todos los patrones.