我有以下设置:
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获得一些方法。
答案 0 :(得分:0)
您遇到的问题与这些循环有关:</ p>
for k, v in kwargs.items():
setattr(self, k, v)
每个类中都有一个,这意味着每个所有之一都将 all 关键字参数设置为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")
,每个类将仅关注其关注的属性。