Метаклассы Scoped;или изменение переменной класса класса A во время __init__ класса B, содержащего вложенные классы, наследуемые от A? - PullRequest
0 голосов
/ 18 мая 2018

Рассмотрим код ниже:

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 быть first имея second_sub_class.attr быть second?Возможно, имея метакласс, область действия которого находится в пределах B?

Несколько моментов:

  1. Я не хочу передавать attr, я хочу установить его, пока Bбудучи инициализированным.
  2. Я не хочу обойти вышеуказанную точку, используя partial, так как он нарушает остальную часть кода, полагаясь на __name__ или __qualname__ или аналогично.
  3. Я хочу сохранить верность существующей структуре в максимально возможной степени.

Ответы [ 2 ]

0 голосов
/ 19 мая 2018

Вы безумно усложняете это:

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'
0 голосов
/ 18 мая 2018

Чтобы решить эту проблему, просто добавьте строку self.attr = self.attr внутри __init__ функции A.Поскольку вы не хотите изменять атрибуты 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)
...