Проблема с внутренними областями классов - PullRequest
0 голосов
/ 08 января 2020

поэтому у меня есть структура классов с несколькими уровнями вложенности внутренних классов для целей пространства имен. Это ничем не отличается от того, чтобы все было плоским, но в этом случае он намного чище и интуитивнее. В основном, мы используем внутренние классы для лучшей организации кода.

Однако я сталкиваюсь с некоторыми проблемами:

Я просто опубликую пример кода, а не попытаюсь объяснить его:

1)

class Namespace1:
    class Class1:
        pass  # base methods go here

        class Subclass1(Namespace1.Class1):
            pass  # extended methods go here

        class Subclass2(Namespace1.Class1):
            pass  # extended methods go here

        class Subclass3(Namespace1.Class1):
            pass  # extended methods go here

    class Class2:
        pass  # base methods go here

        class Subclass1(Namespace1.Class2):
            pass  # extended methods go here

        # etc.

Проблема с подклассами здесь заключается в том, что Namespace1.Class1 еще не существует, когда вы пытаетесь объявить Namespace1.Class1.Subclass1, поэтому он не работает. Я предполагаю, что, вероятно, нет способа исправить это, но я упоминаю об этом просто на случай, если есть какой-то способ достичь этого, о котором я не знаю.

Итак, что я попытался сделать следующее:

class Namespace1:
    class Class1:
        pass  # base methods go here

    class Class1Subclass1(Class1):
        pass  # extended methods go here

    class Class1Subclass2(Class1):
        pass  # extended methods go here

    class Class1Subclass3(Class1):
        pass  # extended methods go here

    class Class2:
        pass  # base methods go here

    class Class2Subclass1(Class2):
        pass  # extended methods go here

        # etc.

Это работает, но мне действительно это не нравится по нескольким причинам:

  • Сейчас мы получаем коллизии пространства имен между подклассами, поэтому мы не можем их вызывать (Subclass1 , Subclass2, ...) больше, и теперь их нужно вызывать (Class1Subclass1, Class1Subclass2, ...)
  • Мы потеряли дополнительные уровни отступов, которые делают визуально явная иерархия, это ужасно, когда вы вложили 4 уровня в глубину и имена ваших классов начинают набирать как 6 слов

Так что я подумал сделать это:

2)

class Namespace1:
    class Class1:
        pass  # base methods go here

    class Class1_:
        class Subclass1(Class1):
            pass  # extended methods go here

        class Subclass2(Class1):
            pass  # extended methods go here

        class Subclass3(Class1):
            pass  # extended methods go here

    class Class2:
        pass  # base methods go here

    class Class2_:
        class Subclass1(Class2):
            pass  # extended methods go here

        # etc.

Это не на 100% идеально (самый хороший способ - что-то вроде примера 1 выше), но теоретически это должно быть возможно сделать. К тому времени, когда интерпретатор приступит к созданию Namespace1.Class1_.Subclass1, Class1 уже должен существовать. У меня проблема в том, что я не знаю, как ссылаться на него, так как я не могу просто ссылаться на него как Namespace1.Class1 (так как Namespace1 еще не существует), и я вне зоны видимости ссылаться на него просто как Class1.

Кто-нибудь имеет представление о том, как я go об этом?

И прежде чем кто-нибудь скажет мне просто использовать иерархию модулей для достижения этой цели Я знаю, что это вариант, но я бы предпочел, чтобы все это было в одном файле таким образом, чтобы был единый обзор, поскольку каждый из этих классов имеет длину всего 3-5 строк (отличается только переопределение одного метода). Для этого конкретного варианта использования хорошо видеть все это в одном месте, и фактический код, который я получил, имеет 3-4 уровня отступов, а некоторые классы имеют более 12 подклассов. Навигация по 100 файлам (каждый из которых может быть длиной 10 строк) была бы кошмаром.

1 Ответ

1 голос
/ 08 января 2020

Вложенные классы хранятся в качестве атрибутов внешнего класса, поэтому вместо указания базового класса каждого вложенного класса непосредственно в его объявлении, что невозможно сделать по причинам, которые вы уже описали, вы можете использовать декоратор класса во внешнем классе, чтобы преобразовать такие атрибуты в подклассы внешнего класса, воссоздав их с вызовом функции type с внешним классом, добавленным к каждому внутреннему классу в качестве базового класса:

def nested_subclasses(cls):
    for name, obj in vars(cls).items():
        if isinstance(obj, type):
            setattr(cls, name, type(name, (cls,), dict(vars(obj))))
    return cls

так что:

class Namespace1:

    @nested_subclasses
    class Class1:
        def foo(self):
            print('bar')

        class Subclass1:
            pass

Namespace1.Class1.Subclass1().foo()

выходы:

bar
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...