Consejos útiles de Python que nunca has conocido antes. Parte 2

Recientemente publicamos una traducción del material, que proporcionó consejos útiles para los programadores de Python. Ese material tiene una secuela que llamamos su atención hoy.



Nomenclatura de corte utilizando la función de corte


Trabajar con los muchos valores especificados por los índices puede convertirse rápidamente en un desastre, tanto en términos de soporte como en términos de legibilidad de código. Una forma de mejorar la situación es usar constantes para los valores especificados por los índices. Pero hay una mejor manera de escribir código de calidad:

#       ID First Name   Last Name line_record = "2    John Smith" ID = slice(0, 8) FIRST_NAME = slice(9, 21) LAST_NAME = slice(22, 27) name = f"{line_record[FIRST_NAME].strip()} {line_record[LAST_NAME].strip()}" # name == "John Smith" 

En este ejemplo, puede ver que al dar los nombres de las slice usando la función de slice , y usando estos nombres para obtener los fragmentos de la cadena, pudimos deshacernos de los intrincados índices. Puede obtener más información sobre el objeto de .start utilizando sus .start , .stop y .step .

Solicitar una contraseña del usuario durante la ejecución del programa


Muchas herramientas de línea de comandos o scripts requieren un nombre de usuario y contraseña para funcionar. Si tiene que escribir dicho programa, puede encontrar getpass módulo getpass :

 import getpass user = getpass.getuser() password = getpass.getpass() #   ... 

Este paquete muy simple le permite solicitar la contraseña de un usuario, así como obtener un nombre de usuario recuperando el nombre con el que inició sesión. Sin embargo, cuando trabaje con contraseñas, debe tener en cuenta que no todos los sistemas admiten la ocultación de contraseñas. Python intentará notificarte. Si esto sucede, verá una advertencia correspondiente en la línea de comando.

Encontrar coincidencias cercanas en cadenas


Ahora hablemos de una característica un poco más misteriosa de la biblioteca estándar de Python. Suponga que se encuentra en una situación en la que necesita, utilizando un concepto como la distancia de Levenshtein , para encontrar palabras en la lista que se parezcan a una determinada línea de entrada. Este problema se puede resolver utilizando el módulo difflib .

 import difflib difflib.get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'], n=2) # returns ['apple', 'ape'] 

El método difflib.get_close_matches las mejores coincidencias "suficientemente buenas". El primer argumento de este método especifica la cadena de búsqueda, el segundo argumento especifica la lista en la que se realiza la búsqueda. Este método puede pasar un argumento opcional n , que especifica el número máximo de coincidencias devueltas. Este método también admite el cutoff argumento con nombre opcional (de forma predeterminada se establece en 0.6 ), que le permite establecer un valor umbral para evaluar coincidencias.

Trabajar con direcciones IP


Si tiene que escribir programas Python para trabajar con la red, esto significa que el módulo ipaddress puede serle muy útil. Una opción para usarlo es generar una lista de direcciones IP a partir de un rango de direcciones especificadas en el formato CIDR (enrutamiento entre dominios sin clase, direccionamiento sin clase).

 import ipaddress net = ipaddress.ip_network('74.125.227.0/29') #      IPv6 # IPv4Network('74.125.227.0/29') for addr in net:    print(addr) # 74.125.227.0 # 74.125.227.1 # 74.125.227.2 # 74.125.227.3 # ... 

Otra característica útil de este módulo es verificar que la dirección IP pertenezca a una determinada red:

 ip = ipaddress.ip_address("74.125.227.3") ip in net # True ip = ipaddress.ip_address("74.125.227.12") ip in net # False 

El módulo ipaddress tiene muchas otras características interesantes de las que no estoy hablando aquí. Lea más sobre él aquí . Es cierto que al usar este módulo, considere las limitaciones con respecto a su trabajo conjunto con otros módulos relacionados con la programación de red. Por ejemplo, no puede usar instancias de IPv4Network como cadenas de direcciones. Los objetos similares para esto primero deben convertirse en cadenas usando str .

Depuración de un programa en la línea de comando


Si usted es uno de los que no quiere usar el IDE y escribe código en Vim o Emacs, entonces puede encontrarse en una situación en la que necesitaría un depurador como los del IDE. ¿Y sabes que? Ya tienes ese depurador. Para usarlo, simplemente ejecute el programa usando una estructura como python3.8 -i . El indicador -i permite, al finalizar el programa, iniciar un shell interactivo. Utilizándolo, puede examinar variables y funciones de llamada. Esta es una característica interesante, pero ¿qué pasa con un depurador real (pdb)? Experimentemos con el siguiente programa simple, cuyo código está en el archivo script.py :

 def func():    return 0 / 0 func() 

Ejecútelo con el python3.8 -i script.py y obtenga lo siguiente:

 #   ... Traceback (most recent call last):  File "script.py", line 4, in <module>    func()  File "script.py", line 2, in func    return 0 / 0 ZeroDivisionError: division by zero >>> import pdb >>> pdb.pm() #      > script.py(2)func() -> return 0 / 0 (Pdb) 

Vemos el lugar del programa donde ocurrió el bloqueo. Establecer un punto de interrupción:

 def func():    breakpoint() # import pdb; pdb.set_trace()    return 0 / 0 func() 

Ejecute el script nuevamente.

script.py(3)func()
-> return 0 / 0
(Pdb) #
(Pdb) step
ZeroDivisionError: division by zero
> script.py(3)func()
-> return 0 / 0
(Pdb)

En la mayoría de las situaciones, el comando de print y los resultados de rastreo son suficientes para depurar los scripts, pero a veces para lidiar con una falla compleja, debe profundizar en el programa y comprender la esencia de lo que está sucediendo. En tales casos, los puntos de interrupción se establecen en el código y se examina el programa. Por ejemplo, observan los argumentos de las funciones, evalúan las expresiones, verifican los valores de las variables o, como se muestra arriba, simplemente ejecutan el código paso a paso. Pdb es un contenedor Python completamente funcional. En este shell, puedes hacer casi cualquier cosa. En el curso del trabajo, algunos comandos específicos del depurador serán útiles, para lo cual se puede encontrar ayuda aquí .

Declarando múltiples constructores en una clase


La sobrecarga de funciones es una de las características que se utilizan ampliamente en varios lenguajes de programación, pero no en Python. Y aunque no puede sobrecargar una función regular en Python, podemos usar algo como sobrecargar los constructores usando métodos de clase:

 import datetime class Date:    def __init__(self, year, month, day):        self.year = year        self.month = month        self.day = day    @classmethod    def today(cls):        t = datetime.datetime.now()        return cls(t.year, t.month, t.day) d = Date.today() print(f"{d.day}/{d.month}/{d.year}") # 14/9/2019 

En una situación similar, en lugar de usar métodos de clase, puede sentirse tentado a poner toda la lógica de los constructores alternativos en __init__ y resolver el problema usando *args , **kwargs y muchas if . El resultado puede ser un código de trabajo, pero este código será difícil de leer y mantener. Aquí recomendaría poner un mínimo de lógica en __init__ y realizar todas las operaciones en métodos / constructores separados. Con este enfoque, tendremos a nuestra disposición un código limpio que será conveniente tanto para el autor de este código como para quien lo use.

Resultados de llamadas de función de almacenamiento en caché utilizando un decorador


¿Alguna vez ha escrito funciones que realizan algunas operaciones largas de lectura / escritura, o más bien cálculos recursivos lentos? Al mismo tiempo, ¿creía que el almacenamiento en caché de los resultados no dañaría tales funciones? Puede almacenar en caché (memorizar) los resultados de una llamada de función utilizando el decorador functools módulo functools :

 from functools import lru_cache import requests @lru_cache(maxsize=32) def get_with_cache(url):    try:        r = requests.get(url)        return r.text    except:        return "Not Found" for url in ["https://google.com/",            "https://martinheinz.dev/",            "https://reddit.com/",            "https://google.com/",            "https://dev.to/martinheinz",            "https://google.com/"]:    get_with_cache(url) print(get_with_cache.cache_info()) # CacheInfo(hits=2, misses=4, maxsize=32, currsize=4) 

En este ejemplo, ejecutamos solicitudes GET cuyos resultados se almacenan en caché (se pueden almacenar en caché hasta 32 resultados). Aquí puede ver que obtenemos información sobre la función de caché utilizando el método cache_info . El decorador también nos proporciona el método clear_cache , que se usa para clear_cache caché. Aquí también me gustaría señalar que el almacenamiento en caché no se puede usar con funciones que tienen efectos secundarios, o con funciones que crean objetos mutables con cada llamada.

Encontrar elementos que se encuentran en el objeto iterable con mayor frecuencia


Estar en la lista de dichos elementos que se encuentran en él con más frecuencia que otros es una tarea muy común. Puede resolverlo, por ejemplo, utilizando el bucle for y un diccionario, que recopilará información sobre la cantidad de elementos idénticos. Pero este enfoque es una pérdida de tiempo. El hecho es que puede resolver estos problemas utilizando la clase Counter del módulo de collections :

 from collections import Counter cheese = ["gouda", "brie", "feta", "cream cheese", "feta", "cheddar",          "parmesan", "parmesan", "cheddar", "mozzarella", "cheddar", "gouda",          "parmesan", "camembert", "emmental", "camembert", "parmesan"] cheese_count = Counter(cheese) print(cheese_count.most_common(3)) # : [('parmesan', 4), ('cheddar', 3), ('gouda', 2)] 

Los mecanismos internos de la clase Counter se basan en un diccionario que almacena la correspondencia de elementos y el número de entradas en la lista. Por lo tanto, el objeto correspondiente se puede usar como un objeto dict regular:

 print(cheese_count["mozzarella"]) # : 1 cheese_count["mozzarella"] += 1 print(cheese_count["mozzarella"]) # : 2 

Además, cuando trabajamos con Counter , tenemos a nuestra disposición el método de update(more_words) , que se utiliza para agregar nuevos elementos al contador. Otra característica útil de Counter es que le permite usar operaciones matemáticas (suma y resta) cuando trabaja con instancias de esta clase.

Resumen


Creo que la mayoría de los consejos dados hoy pueden ser utilizados por quienes escriben en Python casi a diario. Espero que encuentres entre ellos algo que te sea útil.

Estimados lectores! ¿Conoces algún truco interesante de programación de Python? Si es así, por favor compártalos.

Source: https://habr.com/ru/post/485646/


All Articles