我有以下设置:
class A:
def __init__(self, **kwargs):
# Some variables initialized
for k, v in kwargs.items():
setattr(self, k, v)
class B(A):
def __init__(self, **kwargs):
A.__init__(self, **kwargs)
self._b = {}
for k, v in kwargs.items():
setattr(self, k, v)
@property
def b(self):
return self._b
@b.setter
def b(self, value):
self._b.update(value)
class C(B):
def __init__(self, **kwargs):
B.__init__(self, **kwargs)
# Some variables initialized
for k, v in kwargs.items():
setattr(self, k, v)
当我现在创建C
的新实例时,我收到以下错误:
AttributeError: 'C' object has no attribute '_b'
现在这是有道理的,因为当B._b
被调用时,A.__init__(self, **kwargs)
尚未初始化。我可以简单地通过重新排序B的初始化来解决这个问题,
class B(A):
def __init__(self, **kwargs):
self._b = {}
A.__init__(self, **kwargs)
for k, v in kwargs.items():
setattr(self, k, v)
我想了解当我需要在初始化期间将kwargs
从子类传递给父类时,是否存在推荐/最佳实践方法?在我看来,以下事情会起作用,
kwargs
然后弹出它们并将剩余的kwargs
传递给父级初始化希望得到一些方法3。
你遇到的问题是这些循环:
for k, v in kwargs.items():
setattr(self, k, v)
每个类中都有一个,这意味着每个类都将所有关键字参数设置为self
上的属性。
当该循环在A
中运行时,它会失败,因为B
具有需要初始化才能工作的属性。
正如你在问题中提到的那样,快速解决方法是确保B
在运行A.__init__
之前设置它的字典:
class B(A):
def __init__(self, **kwargs):
_b = {} # set this up first
A.__init__(self, **kwargs) # before calling the superclass
for k, v in kwargs.items():
setattr(self, k, v)
但是可能有一种更好的方法可以避免冗余循环。我建议明确命名每个类中您期望的关键字参数。那样的b
只会被B
类看到,不是A
,也不是C
(除了作为kwargs
的一部分)。
class A:
def __init__(self, *, a): # a is keyword-only arg, no kwargs accepted here
self.a = a
class B:
def __init__(self, *, b, **kwargs):
super().__init__(**kwargs) # doesn't mess with b!
self._b = {}
self.b = b
@property
def b(self):
...
class C:
def __init__(self, *, c, **kwargs):
super().__init__(**kwargs)
self.c = c
现在你可以调用C(a="foo", b={1: 2}, c="bar")
,每个类只关注它关心的属性。