Crear objetos de clase de datos anidados en Python

Dataclasses es un módulo de Python incorporado que contiene decoradores y funciones para agregar automáticamente métodos especiales como __init__() y __repr__() a las clases definidas por el usuario.

Dataclass Object es un objeto integrado en el módulo Dataclasses. Esta función se usa como decorador para agregar métodos especiales directamente a una clase definida por el usuario. Este decorador examina la clase para encontrar campos (una variable de clase que contiene una anotación de tipo). Luego, el decorador de clases de datos agrega métodos especiales.

Sintaxis:

@dataclass
class user_defined_class:

Aquí, abordaremos la idea de tener objetos de clase de datos anidados en nuestro programa. Aunque las clases de datos son fáciles de usar, aún aumentan la complejidad del programa en una barra, y anidar tales objetos puede parecer un poco desafiante, pero aquí abordaremos cada escenario y cómo manejarlo.

Objeto de clase de datos anidado

Examine cuidadosamente el siguiente código:

@dataclass
class A:
    a: int
    b: str
  
@dataclass
class B:
    c: str
    d: A

Comenzando con la clase A, está siendo decorado por una clase de datos. Luego, esta clase se anida dentro de la clase B como un campo de B que también está decorado por un objeto de clase de datos. Hasta ahora, este código solo muestra el anidamiento de objetos de clase de datos; a continuación, analizamos cómo empleamos dicha implementación.

# importing module
from dataclasses import dataclass
  
@dataclass
class A:
    a: int
    b: str
  
@dataclass
class B:
    c: str
    d: A
  
# FIRST APPROACH
# creating object for class b with following values 
# c ='hello'
# a = 4
# b ='bye'
data ={'c':'hello', 'd':{'a':4, 'b':'bye'}}
b = B(**data)
print (b)
  
# SECOND APPROACH
data ={'c':'hello', 'd': A(**{'a':4, 'b':'bye'})}
c = B(**data)
print(c)

Producción:

B(c='hello', d={'a': 4, 'b': 'bye'})
B(c='hello', d=A(a=4, b='bye'))

El problema con el primer enfoque es que la salida no da idea sobre el objeto anidado o la clase A y sus atributos, y si ese es el requisito, entonces estamos listos para continuar. El segundo enfoque funciona, pero parece tedioso si tiene varios objetos anidados en sus objetos de clase de datos, no solo esto, con un aumento en la cantidad de objetos anidados, la complejidad del programa también aumentará y también lo hará el método para llamarlos. Por lo tanto, necesitamos una forma de lograr el resultado del segundo enfoque pero sin hacer que el proceso de llamada e inicialización sea complejo.

El problema anterior se puede resolver ajustando el método __init__() generado que verificará los parámetros pasados ​​a kwargs, verificará si algún campo pertenece a un tipo de campo de clase de datos y si genera el objeto anidado antes del __init__() original.

Lo que esto significa se muestra a continuación:

from dataclasses import dataclass, is_dataclass
  
# decorator to wrap original __init__
def nested_deco(*args, **kwargs):
      
    def wrapper(check_class):
          
        # passing class to investigate
        check_class = dataclass(check_class, **kwargs)
        o_init = check_class.__init__
          
        def __init__(self, *args, **kwargs):
              
            for name, value in kwargs.items():
                  
                # getting field type
                ft = check_class.__annotations__.get(name, None)
                  
                if is_dataclass(ft) and isinstance(value, dict):
                    obj = ft(**value)
                    kwargs[name]= obj
                o_init(self, *args, **kwargs)
        check_class.__init__=__init__
          
        return check_class
      
    return wrapper(args[0]) if args else wrapper
  
  
@dataclass
class A:
    a: int
    b: str
  
@nested_deco
class B:
    c: str
    d: A
  
  
data ={'c':'hello', 'd':{'a':4, 'b':'bye'}}
b = B(**data)
print (b)

Producción:

B(c='hello', d=A(a=4, b='bye'))

Tenga en cuenta que, aparte de los problemas generados por __init__(), esto tampoco permite que se devuelva __init__=false al código.

Publicación traducida automáticamente

Artículo escrito por vanshikagoyal43 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *