Наследование метаклассов (модуль 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
, Смотрите эту ссылку.