我正在尝试创建一个可以用** kwargs初始化并具有每个字段默认值的类的系统。这是代表我要执行的操作的一些代码:
class Parent(object): #should only have p_var fields
DEFAULTS = {
"p_var_1" : "my name",
"p_var_2" : 2
}
def __init__(self, **kwargs):
for key in DEFAULTS:
#Also include check for list type and copy, not assign
if key in kwargs:
setattr(self, key, kwargs[key])
else:
setattr(self, key, self.DEFAULTS[key])
#Check for super being 'object' - problems?
#if not super() == object:
# super().__init__(**kwargs)
class Gen1(Parent): #should have p_var and G1_var fields
DEFAULTS = {
"G1_var_1" : "Generation 1",
"G1_var_2" : []
}
#redefining only in case if Parent can't check for super
def __init__(self, **kwargs):
for key in DEFAULTS:
#Also include check for list type and copy, not assign
if key in kwargs:
setattr(self, key, kwargs[key])
else:
setattr(self, key, self.DEFAULTS[key])
#check whether super() is object
super().__init__(**kwargs) #pass all args to parent init
class Gen2(Gen1): #should have p_var, G1_var and G2_var fields
DEFAULTS = {
"G2_var_1" : 1337,
"G2_var_2" : (10,4)
}
#After Gen1, redefining __init__ shouldn't be necessary
这样,在设置几个实例之后:
Gen2item1 = Gen2()
Gen2item2 = Gen2(p_var_1 = "different name", G2_var_1 = 666)
Gen2item1将初始化为所有默认值:
Gen2item1.p_var_1是“我的名字”
Gen2item1.p_var_2是2
Gen2item1.G1_var_1是“ Generation 1”
Gen2item1.G1_var_2为[](副本)
Gen2item1.G2_var_1为1337,
Gen2item1.G2_var_2为(10,4)
但是Gen2item1的p_var_1和G2_var_1值将不同,其余的相同。
但是,由于在子类中覆盖了“ DEFAULT”,因此Gen2item1的值如下:
Gen2item1.p_var_1是666
Gen2item1.p_var_2为(10,4)
每个世代(级别)都设置了3次,并且未设置
G1_var
或p_var
值。对于Gen2item2,所有三代__init__
均将G2_var_1设置为666,将G2_var_2设置为(10,4)。因此,最重要的问题是关于为每个类生成一个“默认”字段(dict)的方法,以便:
通过
__init__
调用子类的item = subclass()
时,它将根据'defaults'dict的键从kwargs
中获取参数,通过
setattrib(self, key, value)
设置自己的字段,如果存在来自默认值的键,则从kwargs中获取值,否则从默认值中获取值,并且通过
super()__init__(**kwargs)
将kwarg传递给其父级时,调用其父级的init。然后,父级对子类的相同实例以相同的方式设置由其生成的dict定义的默认值,调用并传递给其父级的
__init__
,依此类推,直到父级为object
,在这种情况下,根本不会被调用/传递参数。我已经阅读了有关元类的信息,这些元类似乎过大了,还有got my hopes high on this,它有一个单独的父类和子类实例。
没有元类,有没有办法实现这样的事情?将默认值存储在外部全局dict中会更好(在这种情况下,将对寻址有所帮助),或者是否有办法建立工厂?
解决了编辑:
super().__init__
可以工作,并且几乎可以满足我的要求,只要它也为要初始化的类(我的项目的详细信息)定义了__init_subclass__
即可。这是对我的问题的解答,并提供了一些有用的信息,说明如何在项目中实现所需的设置。我相信定义一个建立适当的__init__
并在定义类时运行它的类方法就足够了(这是非常新的__init__
似乎有帮助的方法),但是至少要有一些向后的方法-compatibility,看来元类是做到这一点的方法。 最佳答案
您可以使用在Python 3.6中添加到object()
的新类方法:__init_subclass__
当类被子类化时,将调用此方法,该方法使您无需使用元类就可以自定义子类的创建。
您的示例如下所示:
class Base:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__()
for key, value in kwargs.items():
setattr(cls, key, value)
def __init__(self, *args, **kwargs):
super().__init__()
for key, value in kwargs.items():
setattr(self, key, value)
class Parent(Base, p_var_1='my_name', p_var_2=2):
pass
class Gen1(Parent, G1_var_1='Generation 1', G1_var_2=[]):
pass
class Gen2(Gen1, G2_var_1=1337, G2_var_2=(10,4)):
pass