Наследование метаклассов (модуль abc) Python с вложенными классами

Я написал метакласс Python 3, содержащий вложенный метакласс (с помощью abc), например:

class A_M(object, metaclass=abc.ABCMeta):
    class A_nested_M(object, metaclass=abc.ABCMeta):
        def ... # some methods

Теперь, реализуя как

class A(A_M):
     class A_nested(A_nested_M):
        def ...

не работает Итак, я что-то упустил из-за использования метаклассов или этот тип реализации с вложенными метаклассами вообще не работает?

2 ответа

Решение

Первое: вложенность объявлений классов практически бесполезна в Python. Если вы сами не используете иерархию вложенных классов в качестве жестко запрограммированного пространства имен для хранения атрибутов, вы, вероятно, уже поступаете неправильно.

Вы не сказали, в чем заключается ваша (реальная) проблема и чего вы там пытаетесь достичь, и почему вы используете метакласс ABCmeta. Поэтому трудно предложить какие-либо действительно полезные ответы, но мы можем попытаться уточнить некоторые вещи:

Во-первых: вы не пишете метакласс, как вы предлагаете в тексте "Я написал метакласс Python 3, содержащий вложенный метакласс..." - вы создаете обычные классы, в которых метакласс ABCmeta. Но вы не создаете новые метаклассы - вы бы, если бы вы унаследовали от type или из ABCMeta сам - их ваш новый класс будет использоваться в metaclass= параметр последующих (обычных) классов. Это не относится к делу.

Теперь, во-вторых, все, что определено внутри тела вашей внешней A_M класс будет только "видимым" как атрибуты A_M сам. Это источник вашей ошибки - когда вы пытаетесь унаследовать от A_nested_M вы должны написать:

class A_M(object, metaclass=abc.ABCMeta):
    class A_nested_M(object, metaclass=abc.ABCMeta):
        def ... # some methods


class A(A_M):
     class A_nested(A_M.A_nested_M):
        def ...

Увидеть - A_M.A_nested_M заставит Python найти суперкласс для A_nested: в локальных или глобальных пространствах имен нет ссылок на A_nested_M так как он существует только как атрибут A_M вне тела class A_M... заявление.

Тем не менее, это все еще бесполезно. Если вы хотите иметь экземпляры A_nested ссылаются на случаи A класс, вы должны создать эти экземпляры внутри A.__init__() вызов - в этот момент нет разницы, если A_nested объявляется внутри тела класса или на уровне модуля:

class A_M(object, metaclass=abc.ABCMeta):
    pass

class A_nested_M(object, metaclass=abc.ABCMeta):
    def ... # some methods

class A_nested(A_nested_M):
   ...

class A(A_M):
    def __init__(self):
         self.nested = A_nested()

Теперь это может быть полезным. Вы также можете объявить классы фактически вложенными, но единственный способ, которым они могут быть полезны, - это в любом случае создавать их экземпляры. И в отличие от вложенных функций, вложенные классы не имеют доступа к атрибутам или переменным, объявленным в пространстве имен "вложенного" класса (но для ссылки на них по их полному имени. Т.е. в вашем примере, если A класс будет содержать b classmethod, метод внутри A_nested что бы вызвать этот метод должен был бы вызвать A.b() не b())

Вы должны реализовать свой класс следующим образом:

class A(A_M):
     class A_nested(A_M.A_nested_M):
        def ...

Так как A_nested_M является внутренним классом, вы должны получить к нему доступ так же, как и к любому из атрибутов класса, т.е. A_M.A_nested_M, Смотрите эту ссылку.

Другие вопросы по тегам