7 trucos de Python para mejorar tu código
¿Quiere escribir un código más conciso y legible y también incluir tanto significado en una expresión como sea posible? ¿Crees que es mejor leer sobre los trucos de Python una vez que pasar el resto de tus días leyendo documentación innecesaria?
Entonces has venido al lugar correcto. Comenzaremos con pequeños trucos que quizás hayas visto en alguna parte si has trabajado con Python. Pero prometo que habrá más locuras hacia el final del artículo.
1. La veracidad de varios objetos
A diferencia de algunos lenguajes de programación, en Python, un objeto se considera False
solo si está vacío. Esto significa que no necesitas verificar la longitud de una cadena, tupla o diccionario, solo necesitas verificarlo como una expresión booleana.
Por supuesto, 0 - tambiénFalse
, y el resto de números -True
.
Por ejemplo, las siguientes expresiones son equivalentes:
string = 'Test' # ejemplo True # string = '' # ejemplo False si len (cadena)> 0: print ('El objeto string no está vacío') if len (cadena): # Aquí 0 se convierte a Falso print ('El objeto string no está vacío') si cadena! = '': print ('El objeto string no está vacío') if string: # Aquí la cadena vacía se convierte a False print ('El objeto string no está vacío')
En este caso string
es una cadena, pero podría haber un tipo diferente aquí (con los cambios correspondientes en las condiciones del bloque if
).
La opción de estilo "pythonic" más elegante y apropiada sería if string: ...
2. Comprobación de la aparición de una subcadena
Esta es una pista pequeña y bastante obvia, pero ni siquiera yo me he enterado de inmediato. Debería ser obvio que se puede verificar si el elemento requerido está contenido en una tupla, lista, diccionario, usando una construcción if item in list: ...
. ¡Pero también podría funcionar para strings!
Puedes escribirlo así:
string = 'Hola' # Ejemplo True # string = 'Hola' # Ejemplo False if string.find ('Hola')! = -1: print ('¡Éxito!')
Pero será mucho más claro y hermoso así:
string = 'Hola' # Ejemplo True # string = 'Hola' # Ejemplo False if 'Hola' in string: print ('¡Éxito!')
3. Funciones lambda
A veces es necesario pasar una función como argumento o realizar una operación corta pero compleja varias veces. Puedes definir una función de la forma habitual o utilizar lambda, una función pequeña que devuelve el resultado de una sola expresión.
Las siguientes dos definiciones son completamente idénticas:
def add(a,b): return a + b add = lambda a, b: a + b
La ventaja de una función lambda es que es una expresión y puede ser usada dentro de otra expresión. Por ejemplo, puedes usarlas convenientemente en una función map
que llame a una función de expresión para cada elemento de una lista y devuelva una lista de resultados.
squares = map(lambda x: x * x, [1, 2, 3, 4, 5]) # squares = [1, 4, 9, 16, 25]
Sin funciones lambda, por supuesto, tendríamos que definir esta función por separado. De hecho, ahorramos una línea de código y un nombre de variable.
4. Comprensión de listas
Quizás en algún lugar antes de eso ya se podía escuchar el concepto de "list comprehension". Esta es una forma de encajar un bucle for
, un bloque if
y una asignación en una línea.
Comencemos con el ejemplo más simple. Digamos que necesitamos volver a cuadrar todos los elementos de la lista.
Si recientemente has comenzado a escribir en Python, lo más probable es que escribas así:
numbers = [1, 2, 3, 4, 5] squares = [] for number in numbers: squares.append(number * number) # squares = [1, 4, 9, 16, 25]
Puedes utilizar el ejemplo anterior con una función map
:
numbers = [1, 2, 3, 4, 5] squares = map(lambda x: x * x, numbers) # squares = [1, 4, 9, 16, 25]
Sí, este código es definitivamente más corto que el anterior, pero sigue siendo feo. A primera vista, es difícil saber qué está haciendo una función map
(toma una función y una lista como argumentos y aplica la función a cada elemento de la lista). Además, tenemos que definir una función.
Pero resulta que puedes escribir de una forma más sencilla y comprensible:
numbers = [1, 2, 3, 4, 5] squares = [number * number for number in numbers] # squares = [1, 4, 9, 16, 25]
La segunda línea aquí se lee casi como un pseudocódigo ejecutable. ¿Por qué es bueno esto? Incluso sin conocimiento de Python, una persona puede determinar fácilmente qué está haciendo este código.
5. Filtrar la lista
¿Qué pasa si estamos interesados en filtrar la lista? Por ejemplo, desea eliminar todos los elementos pares.
Un novato en la programación de Python escribiría esto:
numbers = [1, 2, 3, 4, 5] odds = [] for number in numbers: if number % 2: odds.append(number) # odds = [1, 3, 5]
Muy simple, ¿verdad? Pero el código tiene 5 líneas de largo, contiene dos niveles de sangría y hace algo completamente trivial.
Es posible reducir el tamaño del código usando la función filter
:
numbers = [1, 2, 3, 4, 5] odds = filter(lambda x: x % 2, numbers) # odds = [1, 3, 5]
Similar a la función de la map
que hablamos anteriormente, filter
acorta el código, pero aún se ve bastante feo.
¿Cómo funciona la función filter
? Como map
, filter
obtiene una función y una lista. Si la función regresa de un elemento True
, el elemento se incluye en la lista resultante.
Sin embargo, podemos hacer esto a través de "Comprensión de listas":
numbers = [1, 2, 3, 4, 5] odds = [number for number in numbers if number % 2] # odds = [1,3,5]
6. Uso simultáneo de map y filter
Ahora podemos usar todo el poder de las comprensiones de listas (por cierto, también se les llama generadores de listas). Ahora intentemos utilizar la visualización y el filtrado de la lista al mismo tiempo. En otras palabras, quiero ver los cuadrados impares de los elementos de la lista.
Un programador de Python sin experiencia escribiría esto:
numbers = [1, 2, 3, 4, 5] odd_squares = [] for number in numbers: if number % 4: odd_squares.append(number * number) # odd_squares = [1, 9, 25]
Por desgracia, el código comenzó a extenderse hacia la derecha. ¿Quizás puedas simplificarlo?
Intentemos usar map
y filter
:
numbers = [1, 2, 3, 4, 5] odd_squares = map(lambda x: x * x, filter(lambda x: x % 2, numbers)) # odd_squares = [1, 9, 25]
Antes map
y filter
era difícil de leer, pero ahora imposible. Evidentemente, esta no es una buena idea.
Intentemos salvar la situación con un generador de listas:
números = [1, 2, 3, 4, 5] odd_squares = [número * número para número en números si número% 2] # odd_squares = [1, 9, 25]
Sí, resultó ser un poco más largo que la lista anterior, incluidos ejemplos, pero me parece bastante legible. Definitivamente mejor que un bucle for
.
Por cierto, el generador de listas filtra y luego lo muestra. Si lo necesitas al revés, será más difícil. Tendremos que usar generaciones anidadas,map
yfilter
, o un bucle regularfor
, lo que sea más simple.
7. Operador de morsa
La nueva forma de asignar una expresión (:=
), o el operador de morsa, fue la función más comentada introducida en la última versión de Python. Se propuso una nueva adición al lenguaje en PEP 572.
Veamos cómo se ve en el código:
(x:= 5) print(x) # Output: 5
Las asignaciones con la ayuda de una morsa deben realizarse entre paréntesis y se escriben dos puntos antes del signo igual. Dentro de los corchetes, se crea una nueva variable o se asigna el valor de una variable existente.
Sigamos adelante y consideremos un ejemplo que revela todo el potencial del operador de morsa:
# sea un contenedor o una secuencia if (n:= len(a)) > 10: print(f'Demasiados elementos, en concreto {n}')
Es decir, simplemente declaramos una nueva variable n
justo en la verificación de condición y luego la usamos en lugar de volver a calcular el valor. A modo de comparación, veamos cómo podríamos haber hecho esto antes:
n = len(a) if n > 10: print(f'Demasiados elementos, en concreto {n}') # o if len (a)> 10: print(f'Demasiados elementos, en concreto {n}')
En el primer caso, aparece una línea extra de código, en la que se declara una variable innecesaria. En el segundo caso, la misma función se llama dos veces, y esto es una pérdida de rendimiento.
Bueno, un par de ejemplos más:
- Reutilizamos el valor en la lista:
foo = [y:= f(x), y * 2, y * 3] # en vez de foo = [f(x), f(x) * 2, f(x) * 3]
- Reutilizando un valor de una condición en comprensiones de listas:
[y for x in data if (y:=f(x))] # en vez de result = [] for x in data: result = f(x) if result: results.append(result)
- Leyendo datos de un archivo dentro de bucles while:
while (block := f.read(256)) != '': process(block) # en vez de while True: stuff() if fail_condition: break