📜  在Python中创建嵌套的数据类对象

📅  最后修改于: 2022-05-13 01:55:45.417000             🧑  作者: Mango

在Python中创建嵌套的数据类对象

Dataclasses 是一个内置的Python模块,它包含用于自动将 __init__() 和 __repr__() 等特殊方法添加到用户定义的类的装饰器和函数。

Dataclass Object 是内置在 Dataclasses 模块中的对象。此函数用作装饰器,可将特殊方法直接添加到用户定义的类中。此装饰器检查类以查找字段(包含类型注释的类变量)。然后数据类装饰器添加特殊方法。

句法:

@dataclass
class user_defined_class:

在这里,我们将解决在程序中嵌套数据类对象的想法。尽管数据类易于使用,但它们仍然会增加程序的复杂性,并且嵌套此类对象可能会有些挑战,但在这里我们将介绍每种情况以及如何处理它。

嵌套数据类对象

仔细检查以下代码:

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

从 A 类开始,它被一个数据类修饰。然后,该类作为 B 的字段嵌套在 B 类中,该字段也被数据类对象修饰。到目前为止,这段代码只展示了数据类对象的嵌套,接下来我们讨论如何使用这样的实现。

# 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)

输出:

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

第一种方法的问题在于,输出不知道嵌套对象或 A 类及其属性,如果这是一个要求,那么我们就可以开始了。第二种方法可以解决问题,但是如果您的数据类对象中有多个嵌套对象,这似乎很乏味,不仅如此,随着嵌套对象数量的增加,程序的复杂性也会增加,调用它们的方法也会增加。因此,我们需要一种方法来实现第二种方法的输出,但又不会使调用和初始化过程变得复杂。

上述问题可以通过包装生成的 __init__() 方法来解决,该方法将检查传递给 kwargs 的参数,检查是否有任何字段属于数据类字段类型,以及它是否在原始 __init__() 之前生成嵌套对象。

这意味着什么如下所示:

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)

输出:

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

请注意,除了 __init__() 产生的问题之外,这也不允许将 __init__=false 返回到代码中。