comprehension - Usar la clase de Python como un contenedor de datos
python dictionary (11)
¿Qué hay de Prodict :
group = Prodict(a=1, b=2, c=3)
group.d = 4
Y si quiere que la conversión de tipo automático y el código automático se completen (inteli-sense):
class Person(Prodict):
name: str
email: str
rate: int
john = Person(name=''John'', email=''[email protected]'')
john.rate = 7
john.age = 35 # dynamic
A veces tiene sentido agrupar datos relacionados. Tiendo a hacerlo con un dict, por ejemplo,
self.group = dict(a=1, b=2, c=3)
print self.group[''a'']
Uno de mis colegas prefiere crear una clase
class groupClass(object):
def __init__(a, b, c):
self.a = a
self.b = b
self.c = c
self.group = groupClass(1, 2, 3)
print self.group.a
Tenga en cuenta que no estamos definiendo ningún método de clase.
Me gusta usar un dict porque me gusta minimizar el número de líneas de código. Mi colega piensa que el código es más legible si usa una clase, y facilita agregar métodos a la clase en el futuro.
cuál prefieres y por qué?
En un lenguaje que lo soporte, usaría una struct
. Un diccionario sería el más cercano a una estructura en Python, al menos hasta donde yo lo veo.
Sin mencionar, podrías agregar un método a un diccionario de todos modos si realmente quisieras;)
Hay una nueva propuesta que pretende implementar exactamente lo que está buscando, llamado clases de datos . Mira esto.
Usar una clase sobre un dict es una cuestión de preferencia. Personalmente prefiero usar un dict cuando las claves no se conocen a priori. (Como un contenedor de mapeo).
El uso de una clase para contener datos significa que puede proporcionar documentación a los atributos de la clase.
Personalmente, tal vez la razón más importante para usar una clase es hacer uso de la función de autocompletar de IDE. (técnicamente una razón débil, pero muy útil en la práctica)
No estoy de acuerdo con que el código sea más legible usando una clase sin métodos. Por lo general, espera la funcionalidad de una clase, no solo de datos.
Así que iría por un dict hasta que surja la necesidad de funcionalidad, y luego el constructor de la clase podría recibir un dict :-)
Por cierto, creo que Python 3.7 implementado @ dataclass es la forma más simple y eficiente de implementar clases como contenedores de datos.
@dataclass
class Data:
a: list
b: str #default variables go after non default variables
c: bool = False
def func():
return A(a="hello")
print(func())
La salida sería: hello
Es muy similar a Scala como clase de caso y la forma más fácil de usar una clase como contenedor.
Prefiero seguir a YAGNI y usar un dict.
Puede combinar ventajas de dict y class juntos, utilizando alguna clase de contenedor heredada de dict. No necesita escribir un código repetitivo, y al mismo tiempo puede usar la notación de puntos.
class ObjDict(dict):
def __getattr__(self,attr):
return self[attr]
def __setattr__(self,attr,value):
self[attr]=value
self.group = ObjDict(a=1, b=2, c=3)
print self.group.a
Si en realidad nunca define ningún método de clase, un dict o un namedtuple tienen mucho más sentido, en mi opinión. Simple + builtin es bueno! A cada cual, lo suyo.
Tu camino es mejor. No intente anticiparse demasiado al futuro, ya que no es probable que tenga éxito.
Sin embargo, a veces puede tener sentido utilizar algo como una estructura C , por ejemplo, si desea identificar diferentes tipos en lugar de usar dicts para todo.
Un dict es obviamente apropiado para esa situación. Fue diseñado específicamente para ese caso de uso. A menos que realmente vaya a usar la clase como clase, no tiene sentido reinventar la rueda e incurrir en gastos adicionales / perder el espacio de una clase que actúa como un diccionario incorrecto (sin funciones de diccionario).
Fondo
R. Hettinger presentó un resumen de contenedores de datos alternativos basados en atributos en la reunión de vacaciones 2017 de SF Python. Ver su tweet y su mazo de diapositivas . También dio una talk en PyCon 2018 sobre clases de datos.
Otros tipos de contenedor de datos se mencionan en este article y predominantemente en la documentación de Python 3 (ver enlaces a continuación).
Opciones
Alternativas en la biblioteca estándar
-
collections.namedtuple
: tuple con atributos -
typing.NamedTuple
: tupla sub-classable (ver esta post comparándolo connamedtuple
) -
types.SimpleNamedspace
: clase simple con declaración de clase opcional -
types.MappingProxy
: dict de solo lectura -
enum.Enum
: colección restringida de constantes relacionadas (se comporta como una clase) -
dataclasses.dataclass
: mutable namedtuple con clases predeterminadas / sin palabras clave
Opciones externas
- records : mutable namedtuple
- bunches : agregar acceso de atributo a dicts (inspiración para
SimpleNamedspace
) - box : wrap dicts con funcionalidad de búsqueda de estilo punto
- attrdict : accede a los elementos de un mapeo como claves o atributos
- fields : eliminar texto estándar de las clases de contenedor.
- namedlist : namedlist mutables, tipo tupla con valores por defecto de E. Smith
¿Cúal?
Decidir qué opción usar depende de la situación. Por lo general, un diccionario mutable pasado de moda o un nombre inmutable es lo suficientemente bueno. Las clases de datos son la adición más nueva (Python 3.7a) que ofrece tanto mutabilidad como inmutabilidad opcional , con la promesa de una repetición reducida según lo inspirado por el proyecto attrs .