作用域元classes;或在 class B 的 __init__ 期间更改 class A 的 class 变量,其中包含从 A 继承的嵌套 classes?

Scoped metaclasses; or changing class variable of class A during the __init__ of class B containing nested classes inheriting from A?

考虑以下代码:

class A(object):
    attr = None

    def __init__(self):
        assert A.attr is not None


class B(object):
    def __init__(self, attr):
        A.attr = attr

    class C(A):
        def __init__(self):
            super().__init__()

    class D(A):
        def __init__(self):
            super().__init__()

    nested_classes = {cls.__name__: cls for cls in {C, D}}

上面的内容似乎没有按我的意图工作,因为:

>>> first_class = B("first")

>>> first_sub_class = first_class.C()

>>> first_sub_class.attr
'first'

>>> second_class = B("second")

>>> second_sub_class = second_class.C()

>>> second_sub_class.attr
'second'

>>> first_sub_class.attr
'second'

有没有办法让 first_sub_class.attr 成为 firstsecond_sub_class.attr 成为 second?可能通过具有范围在 B 内的元类?

几点:

  1. 我不想传递attr,我想在B初始化的时候设置它。
  2. 我不想通过使用 partial 绕过上述观点,因为它破坏了依赖 __name____qualname__ 或类似代码的其余代码。
  3. 我想尽可能忠实于当前的结构。

要解决此问题,只需在 A__init__ 函数中添加行 self.attr = self.attr。由于您不想更改 A 的属性,因此您必须进行以下更改:

class A(object):
    attr = None

    def __init__(self):
        assert self.attr is not None # Don't refer to A, but to self to get the correct value
        self.attr = self.attr


class B(object):
    def __init__(self, attr):
        self.attr = attr # Don't edit A, just save the value in own instance

    def __getattribute__(self, item): # completely added, does some magic to ensure class.attr is set correctly 
        if item in B.nested_classes:
            c = B.nested_classes[item]
            c.attr = self.attr
            return c
        return super().__getattribute__(item)

    class C(A):
        def __init__(self):
            super().__init__()

    class D(A):
        def __init__(self):
            super().__init__()

    nested_classes = {cls.__name__: cls for cls in {C, D}}


first_class = B("first")
first_sub_class = first_class.C()
print(first_sub_class.attr)
second_class = B("second")
second_sub_class = second_class.C()
print(second_sub_class.attr)
print(first_sub_class.attr)

你太复杂了:

class A:
    def __init__(self, attr):
        self.attr = attr

class C(A):
    pass

class D(A):
    pass

class B:
    def __init__(self, attr):
        self.attr = attr

    def C(self):
        return C(self.attr)

    def D(self):
        return D(self.attr)

完全符合要求:

>>> first_class = B("first")

>>> first_sub_class = first_class.C()

>>> first_sub_class.attr
'first'

>>> second_class = B("second")

>>> second_sub_class = second_class.C()

>>> second_sub_class.attr
'second'

>>> first_sub_class.attr
'first'