Domine Python Attrs: construya data classes avanzadas con ejemplos prácticos

El paquete Python Attrs le permite crear data classes avanzadas usando anotaciones simples. Por supuesto, Python tiene su propio módulo nativo dataclass, pero el paquete attrs ofrece un par de características extra que podrían gustarle.
Instalar attrs
El paquete attrs no forma parte de la librería estándar, así que necesitarás instalarlo con pip install o algo similar, como Pipenv. Probablemente también quieras crear un entorno virtual para no interferir con otros proyectos. El paquete se llama attrs, así que instalarlo se vería así:
$ pip install attrs
# o con pipenv:
$ pipenv install attrs
Attrs vs data classes
Los autores de attrs de hecho trabajaron en el PEP que introdujo las data classes en Python. Las data classes nativas de Python se mantienen intencionalmente más simples y fáciles de entender, mientras attrs ofrece toda la gama de características que podrías querer.
Algunas razones para elegir attrs sobre las data classes integradas:
- Usas una versión de Python anterior a 3.7.
attrste cubre ya que soporta todas las versiones mainstream, incluyendo CPython 2.7 y PyPy. - Quieres más características:
attrsofrece validadores y convertidores. - Quieres rendimiento óptimo y uso mínimo de memoria usando slotted classes de
attrs.
Ejemplo básico de Python attrs
Veamos un ejemplo muy básico primero:
import attr
@attr.s
class Person(object):
name = attr.ib(default='John')
surname = attr.ib(default='Doe')
age = attr.ib(init=False)
p = Person()
print(p)
p = Person('Bill', 'Gates')
p.age = 60
print(p)
# Salida:
# Person(name='John', surname='Doe', age=NOTHING)
# Person(name='Bill', surname='Gates', age=60)
Un par de observaciones:
- La sintaxis es menos elegante y más verbosa que la de data classes, pero obtienes características extra a cambio.
- Similar a data classes, obtienes una representación formateada bonita de tus datos al imprimirla.
- El paquete
attrsusa nombres inteligentemente elegidos comoattr.ib, así que solo necesitas importarattr. Alternativamente, puedes importar los nombres completos. Por ejemplo confrom attr import attrib, attrs, y usar esos nombres. La funcionalidad es la misma.
Veamos ahora las características más importantes que este paquete ofrece sobre data classes regulares: validadores y convertidores.
Ejemplo de validador en Python attrs
Puedes añadir validadores a tu data class de attrs de dos formas:
- Usando un decorador.
- Proporcionando una función invocable (callable).
Demostraré primero el método de función invocable. attrs ofrece varios validadores listos para usar, de los cuales usaremos el validador instance_of en el siguiente ejemplo:
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.instance_of(int))
>>> C(42)
C(x=42)
>>> C("una cadena")
Traceback (most recent call last):
...
TypeError: ("'x' must be <type 'int'> (got 'una cadena' that is a <type 'str'>).", ...
Como intentamos crear un objeto C con un valor de cadena para x, el validador instance_of lanza un error porque requiere un tipo int en lugar de cadena.
Definamos ahora nuestro propio validador:
import attr
@attr.s
class DivisibleByTwo(object):
x = attr.ib()
@x.validator
def check(self, attribute, value):
if value % 2 != 0:
raise ValueError(f'{value} no es divisible por 2')
print(DivisibleByTwo(60))
print(DivisibleByTwo(11))
# La salida será algo como:
# DivisibleByTwo(x=60)
# ...
# ValueError: 11 no es divisible por 2
Ejemplo de convertidor en Python attrs
Un convertidor toma el valor que se establece y lo convierte automáticamente. Puedes usarlo para todo tipo de propósitos. Un ejemplo es convertir automáticamente un valor a int. Empecemos de nuevo con una función invocable, en este caso simplemente usamos int() de Python:
import attr
@attr.s
class C(object):
x = attr.ib(converter=int)
c = C("1")
print(c)
# Salida:
# C(x=1)
Nuestra entrada (la cadena «1») se convirtió a entero automáticamente. Como los convertidores se ejecutan antes que los validadores, puedes validar el valor final después de la conversión. P. ej., podrías combinar los dos ejemplos anteriores para convertir primero cualquier entrada a int y luego verificar si el valor es divisible por dos.
Usar slots con Python attrs
Finalmente, puedes decirle a attrs que use slotted classes. Las slotted classes tienen algunas ventajas sobre clases regulares:
- Tienen una huella de memoria pequeña.
- Son más rápidas.
En resumen, con una slotted class declaras explícitamente qué atributos de instancia esperas que tengan tus objetos. Así, Python puede omitir algunas comprobaciones, resultando en menos uso de memoria y ligeros aumentos de velocidad. Puedes encontrar más detalles en la documentación de attrs.
Sin embargo, las slotted classes también tienen advertencias, especialmente cuando las creas manualmente. Afortunadamente, attrs nos ofrece una forma simple de habilitar la característica:
import attr
@attr.s(slots=True)
class YourClassName:
...
Seguir aprendiendo
- Nuestro artículo sobre data classes de Python
- Nuestro tutorial sobre clases y objetos en Python
- Para más ejemplos, visita la página de ejemplos de
attrs
python
- Dominando tipos de datos en Python: Guía práctica
- Domine el Método strip() de Python: Guía Completa y Ejemplos Prácticos
- Domine str.count() en Python: Cómo Contar Caracteres y Subcadenas con Ejemplos
- Función round() en Python explicada con ejemplos prácticos
- Dominando la función map() de Python: sintaxis, ejemplos y mejores prácticas
- Python timeit(): medición de tiempo de ejecución con ejemplos prácticos
- Counter de collections en Python: conteo eficiente, actualización y operaciones aritméticas
- Python time.sleep(): cómo añadir retrasos en tu código (ejemplos)
- Python list.count(): Guía Experta con Ejemplos Prácticos
- Python list.index(): Cómo Encontrar Posiciones de Elementos con Ejemplos Prácticos
- Programación de Extensiones en Python con C: Crea Módulos Nativos Rápidos