Кто-нибудь использует мета-мета-классы/мета-мета-мета-классы в Python/других языках?

Недавно я обнаружил метаклассы в python.

В основном метаклассом в python является класс, который создает класс. Существует много полезных причин, по которым вы хотели бы это сделать - например, любая инициализация класса. Регистрация классов на фабриках, комплексная проверка атрибутов, изменение работы наследования и т.д. Все это становится не только возможным, но и простым.

Но в python метаклассы также являются простыми классами. Итак, я начал задаваться вопросом, может ли абстракция с пользой пойти выше, и мне кажется, что она может и что:

  • метакласс соответствует или реализует роль в шаблоне (как в языках шаблонов GOF).
  • Мета-метакласс - это сам шаблон (если мы разрешаем ему создавать кортежи классов, представляющих абстрактные роли, а не только один класс)
  • мета-мета-метакласс - это шаблон factory, который соответствует группам шаблонов GOF, например. Креативная, структурная, поведенческая. A factory, где вы могли бы описать случай определенного типа проблемы, и это даст вам набор классов, которые его разрешили.
  • meta-meta-meta-metaclass (насколько я мог бы идти), это шаблон factory factory, factory, о котором вы могли бы рассказать о типе своей проблемы, и это даст вам шаблон factory, чтобы спросить.

Я нашел несколько вещей об этом в Интернете, но в основном не очень полезен. Одна из проблем заключается в том, что разные языки немного определяют метаклассы.

Кто-нибудь еще использовал метаклассы, подобные этому в python/где-либо еще, или видел, что это используется в дикой природе, или думал об этом? Каковы аналоги на других языках? Например. в С++ насколько глубока рекурсия шаблона?

Я бы очень хотел исследовать его дальше.

Ответы

Ответ 1

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

5 → Целое число → Integer класс → Метакласс → Класс метакласса → Метакласс → ... (он петли)

Где '- > ' обозначает "является экземпляром".

Ответ 2

Это напоминает мне о вечном стремлении, которое некоторые люди, похоже, делают, чтобы сделать "общую реализацию шаблона". Как и factory, который может создать любой объект (включая другой factory), или универсальную среду инъекций зависимостей, которая намного сложнее чтобы управлять, чем просто писать код, который на самом деле что-то делает.

Мне приходилось иметь дело с людьми, увлеченными абстракцией, до точки зрения, когда я управлял проектом Zend Framework. Я отклонил кучу предложений по созданию компонентов, которые ничего не сделали, они были просто волшебными реализациями шаблонов GoF, как будто шаблон был целью сам по себе, а не средством достижения цели.

Там есть точка уменьшения прибыли для абстракции. Некоторая абстракция велика, но в итоге вам нужно написать код, который сделает что-то полезное.

В противном случае это просто черепахи до конца.

Ответ 3

Чтобы ответить на ваш вопрос: нет.

Не стесняйтесь исследовать его дальше.

Обратите внимание, однако, что вы сконфигурировали шаблоны проектирования (которые являются просто идеями) с кодом (который является реализацией).

Хороший код часто отражает ряд взаимосвязанных шаблонов проектирования. Там нет простого способа формализовать это. Лучшее, что вы можете сделать, это хорошая картина, хорошо написанные docstrings и имена методов, которые отражают различные шаблоны дизайна.

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


Edit

"Являются ли классы, которые создают метаклассы действительно настолько глупыми? Как их утилита внезапно заканчивается?"

Класс, создающий класс, хорош. Это в значительной степени. Тот факт, что целевой класс является мета-классом или абстрактным суперклассом или конкретным классом, не имеет значения. Метаклассы создают классы. Они могут создавать другие метаклассы, что странно, но они все еще просто метаклассы, создающие классы.

Утилита "внезапно" заканчивается, потому что в метаклассе нет необходимости (или даже писать), что делает другой метакласс. Дело не в том, что оно "внезапно" становится глупым. Это то, что там ничего не полезно.

Как я семя, не стесняйтесь исследовать его. Например, на самом деле напишите метакласс, который создает другой метакласс. Повеселись. Там может быть что-то полезное.

Точка OO - это написать определения классов, которые моделируют объекты реального мира. Таким образом, метакласс иногда удобен для определения сквозных аспектов нескольких связанных классов. (Это способ сделать какое-то Аспектно-ориентированное программирование.) Что все метаклассы действительно могут сделать; это место для хранения нескольких функций, таких как __new__(), которые не являются надлежащими частями самого класса.

Ответ 4

Во время конференции "История языков программирования" в 2007 году Саймон Пейтон Джонс отметил, что Haskell позволяет метапрограммирование с использованием классов типа, но это действительно черепахи вплоть до конца. Вы можете мета-мета-мета-мета и т.д. В Haskell, но он никогда не слышал о том, чтобы кто-то использовал более трех уровней косвенности.

Гай Стил указал, что это то же самое в Lisp и Scheme. Вы можете выполнять метапрограммирование с использованием обратных циклов и оценок (вы можете думать об обратном, как лямбда Python, вроде как), но он никогда не видел более трех обратных ссылок.

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

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

Ответ 5

С тех пор, как я впервые понял метаклассы в Python, я продолжал задаваться вопросом: "Что можно сделать с мета-мета-классом?". Это по крайней мере 10 лет назад - и теперь, всего пару месяцев назад, мне стало ясно, что в создании класса Python существует один механизм, который фактически включает класс мета-мета. И поэтому можно попытаться представить себе какое-то использование для этого.

Чтобы воспроизвести экземпляр объекта в Python: всякий раз, когда экземпляр объекта создается на Python, "вызывает" его класс с тем же синтаксисом, который используется для вызова обычной функции, класс __new__ и __init__. То, что "организует" вызов этих методов в классе, - это именно метод class'metaclass '__call__. Обычно, когда вы пишете метакласс в Python, настраивается либо метод __new__, либо __init__ метакласса.

Итак, получается, что, написав класс "мета-мета", можно настроить его метод __call__ и, таким образом, управлять переданными параметрами и метаклассовыми методами __new__ и __init__, а если некоторые другие код следует вызывать до этого после. В конце концов получается, что сами metcalsses обычно жестко закодированы, и нужно лишь несколько, если они есть, даже в очень больших проектах. Таким образом, любая настройка, которая может выполняться при вызове "meta meta", обычно выполняется непосредственно на самом метаклассе.

И они, есть те другие менее часто используемые применения для метаклассов Python - можно настроить метод __add__ в метаклассе, чтобы классы, которые они определяют, "добавляются", и создают производный класс, имеющий два добавленных класса, как суперкласса. Этот механизм отлично подходит и для метаклассов, поэтому, так как мы "имеем некоторый фактический код", следует примеру класса "мета-мета", который позволяет составлять "метаклассы" для класса, просто добавляя их в объявление класса

class MM(type):
    def __add__(cls, other):
        metacls = cls.__class__
        return metacls(cls.__name__ + other.__name__, (cls, other), {})

class M1(type, metaclass=MM):
    def __new__(metacls, name, bases, namespace):
        namespace["M1"] = "here"
        print("At M1 creation")
        return super().__new__(metacls, name, bases, namespace)

class M2(type, metaclass=MM):
    def __new__(metacls, name, bases, namespace):
        namespace["M2"] = "there"
        print("At M2 creation")
        return super().__new__(metacls, name, bases, namespace)

И мы видим, что работаем на интерактивной консоли:

In [22]: class Base(metaclass = M1 + M2): 
    ...:     pass
    ...: 
At M1 creation
At M2 creation

Обратите внимание, что, поскольку разные метаклассы в Python обычно трудно комбинировать, это может быть полезно, если позволить метаклассу, создаваемому пользователем, быть объединенным с библиотекой или stdlib, без этого явно не должно быть явно объявлено родителем бывший:

In [23]: import abc

In [24]: class Combined(metaclass=M1 + abc.ABCMeta):
    ...:     pass
    ...: 
At M1 creation