在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 返回到代码中。