Visión general
La pregunta ha sido abordada. Sin embargo, esta respuesta agrega algunos ejemplos prácticos para ayudar en la comprensión básica de las clases de datos.
¿Qué son exactamente las clases de datos de Python y cuándo es mejor usarlas?
- generadores de código : generar código repetitivo; puede optar por implementar métodos especiales en una clase regular o hacer que una clase de datos los implemente automáticamente.
- Contenedores de datos : estructuras que contienen datos (por ejemplo, tuplas y dictados), a menudo con acceso punteado, de atributos, como clases
namedtuple
y otros .
"nombre de tuplas mutables con [s] predeterminado"
Esto es lo que significa la última frase:
- mutable : por defecto, los atributos de la clase de datos se pueden reasignar. Opcionalmente, puede hacerlos inmutables (ver ejemplos a continuación).
- namedtuple : tienes puntos, acceso a atributos como una
namedtuple
o una clase regular.
- predeterminado : puede asignar valores predeterminados a los atributos.
En comparación con las clases comunes, principalmente ahorras escribiendo código repetitivo.
Caracteristicas
Esta es una descripción general de las características de la clase de datos (TL; DR? Consulte la tabla de resumen en la siguiente sección).
Lo que obtienes
Estas son las características que obtiene por defecto de las clases de datos.
Atributos + Representación + Comparación
import dataclasses
@dataclasses.dataclass
#@dataclasses.dataclass() # alternative
class Color:
r : int = 0
g : int = 0
b : int = 0
Estos valores predeterminados se proporcionan configurando automáticamente las siguientes palabras clave en True
:
@dataclasses.dataclass(init=True, repr=True, eq=True)
Lo que puedes encender
Las funciones adicionales están disponibles si las palabras clave apropiadas están establecidas en True
.
Orden
@dataclasses.dataclass(order=True)
class Color:
r : int = 0
g : int = 0
b : int = 0
Ahora se implementan los métodos de pedido (operadores de sobrecarga:) < > <= >=
, de manera similar a functools.total_ordering
las pruebas de igualdad más fuertes.
Hashable, Mutable
@dataclasses.dataclass(unsafe_hash=True) # override base `__hash__`
class Color:
...
Aunque el objeto es potencialmente mutable (posiblemente no deseado), se implementa un hash.
Hashable, inmutable
@dataclasses.dataclass(frozen=True) # `eq=True` (default) to be immutable
class Color:
...
Ahora se implementa un hash y no se permite cambiar el objeto o asignar atributos.
En general, el objeto es hashable si unsafe_hash=True
o frozen=True
.
Consulte también la tabla lógica de hashing original con más detalles.
Lo que no entiendes
Para obtener las siguientes características, se deben implementar métodos especiales manualmente:
Desempacando
@dataclasses.dataclass
class Color:
r : int = 0
g : int = 0
b : int = 0
def __iter__(self):
yield from dataclasses.astuple(self)
Mejoramiento
@dataclasses.dataclass
class SlottedColor:
__slots__ = ["r", "b", "g"]
r : int
g : int
b : int
El tamaño del objeto ahora se reduce:
>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888
En algunas circunstancias, __slots__
también mejora la velocidad de creación de instancias y acceso a atributos. Además, los espacios no permiten asignaciones predeterminadas; de lo contrario, ValueError
se plantea a.
Vea más sobre tragamonedas en esta publicación de blog .
Tabla de resumen
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Feature | Keyword | Example | Implement in a Class |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Attributes | init | Color().r -> 0 | __init__ |
| Representation | repr | Color() -> Color(r=0, g=0, b=0) | __repr__ |
| Comparision* | eq | Color() == Color(0, 0, 0) -> True | __eq__ |
| | | | |
| Order | order | sorted([Color(0, 50, 0), Color()]) -> ... | __lt__, __le__, __gt__, __ge__ |
| Hashable | unsafe_hash/frozen | {Color(), {Color()}} -> {Color(r=0, g=0, b=0)} | __hash__ |
| Immutable | frozen + eq | Color().r = 10 -> TypeError | __setattr__, __delattr__ |
| | | | |
| Unpacking+ | - | r, g, b = Color() | __iter__ |
| Optimization+ | - | sys.getsizeof(SlottedColor) -> 888 | __slots__ |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
+ Estos métodos no se generan automáticamente y requieren implementación manual en una clase de datos.
* __ne__
no es necesario y, por lo tanto, no se implementa .
Características adicionales
Post-inicialización
@dataclasses.dataclass
class RGBA:
r : int = 0
g : int = 0
b : int = 0
a : float = 1.0
def __post_init__(self):
self.a : int = int(self.a * 255)
RGBA(127, 0, 255, 0.5)
# RGBA(r=127, g=0, b=255, a=127)
Herencia
@dataclasses.dataclass
class RGBA(Color):
a : int = 0
Conversiones
Convierta una clase de datos en una tupla o un dict, recursivamente :
>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{r: 128, g: 0, b: 255}
Limitaciones
Referencias
- Charla de R. Hettinger sobre Dataclasses: el generador de código para finalizar todos los generadores de código
- Charla de T. Hunner sobre Clases más fáciles: Clases de Python sin todo lo rudo
- Documentación de Python sobre detalles de hashing
- Guía de Real Python sobre La guía definitiva para las clases de datos en Python 3.7
- La publicación de blog de A. Shaw en Un breve recorrido por las clases de datos de Python 3.7
- El repositorio github de E. Smith en clases de datos
namedtuple
Los s son inmutables y no pueden tener valores predeterminados para los atributos, mientras que las clases de datos son mutables y pueden tenerlos.