在类继承链中传递kwargs

问题描述 投票:0回答:1

我有以下设置:

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从子类传递给父类时,是否存在推荐/最佳实践方法?在我看来,以下事情会起作用,

  1. 像我上面那样重新排序初始化
  2. 在每个子类中分配kwargs然后弹出它们并将剩余的kwargs传递给父级初始化
  3. 更好的东西

希望得到一些方法3。

python inheritance kwargs method-resolution-order
1个回答
0
投票

你遇到的问题是这些循环:

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"),每个类只关注它关心的属性。

© www.soinside.com 2019 - 2024. All rights reserved.