Jump to content

Метакласс

В объектно-ориентированном программировании метакласс класс — это , которого экземпляры сами являются классами. В отличие от обычных классов, определяющих поведение объектов, метаклассы определяют поведение классов и их экземпляров. Не все объектно-ориентированные языки программирования поддерживают концепцию метаклассов. Для тех, кто это делает, степень контроля метаклассов над поведением классов варьируется. Метаклассы часто реализуются, рассматривая классы как первоклассных граждан , превращая метакласс в объект, который создает эти классы и управляет ими. Каждый язык программирования придерживается своего собственного протокола метаобъектов , который представляет собой правила, определяющие взаимодействие между объектами, классами и метаклассами. [1] Метаклассы используются для автоматизации генерации кода и улучшения разработки инфраструктуры. [2]

Пример Python

[ редактировать ]

В Python встроенный класс type это метакласс. [3] [4] [5] Рассмотрим этот простой класс Python:

class Car:
    def __init__(self, make: str, model: str, year: int, color: str):
        self.make = make
        self.model = model
        self.year = year
        self.color = color

    @property
    def description(self) -> str:
        """Return a description of this car."""
        return f"{self.color} {self.make} {self.model}"

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

Приведенный выше пример содержит некоторый избыточный код для четырех атрибутов. make, model, year, и color. Эту избыточность можно устранить с помощью специального метакласса. В Python метакласс проще всего определить как подкласс type.

class AttributeInitType(type):
    def __call__(self, *args, **kwargs):
        """Create a new instance."""

        # First, create the object in the normal default way.
        obj = type.__call__(self, *args)

        # Additionally, set attributes on the new object.
        for name, value in kwargs.items():
            setattr(obj, name, value)

        # Return the new object.
        return obj

Этот метакласс переопределяет только создание объекта. Все остальные аспекты поведения классов и объектов по-прежнему обрабатываются type.

Теперь класс Car может быть переписан для использования этого метакласса. В Python 3 это делается путем предоставления «аргумента ключевого слова». metaclass к определению класса:

class Car(object, metaclass=AttributeInitType):
    @property
    def description(self) -> str:
        """Return a description of this car."""
        return " ".join(str(value) for value in self.__dict__.values())

Полученный объект Car может быть создан как обычно, но может содержать любое количество аргументов ключевого слова:

new_car = Car(make='Toyota', model='Prius', year=2005, color='Green', engine='Hybrid')

В Смолталке-80

[ редактировать ]
Иерархия метаклассов Smalltalk-80 как диаграмма UML
Диаграмма отношений наследования и экземпляров между классами и метаклассами в Smalltalk

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

Например, автомобильный объект c является экземпляром класса Car. В свою очередь, класс Car снова является объектом и, как таковой, экземпляром метакласса Car называется Car class. Обратите внимание на пробел в названии метакласса. Имя метакласса — это выражение Smalltalk, при вычислении которого создается объект метакласса. Таким образом оценивая Car class приводит к объекту метакласса для Car чьё имя Car class (это можно подтвердить, оценив Car class name который возвращает имя метакласса Car.)

Методы класса фактически принадлежат метаклассу, так же как методы экземпляра фактически принадлежат классу. Когда сообщение отправляется на объект 2, поиск метода начинается в Integer. Если он не найден, он переходит вверх по цепочке суперклассов, останавливаясь на объекте, независимо от того, найден он или нет.

Когда сообщение отправляется на Integer поиск метода начинается в Integer class и переходит вверх по цепочке суперклассов к Object class. Обратите внимание, что до сих пор цепочка наследования метаклассов точно соответствует цепочке наследования классов. Но цепочка метаклассов простирается дальше, потому что Object class является подклассом Class. Все метаклассы являются подклассами класса Class.

В ранних Smalltalks был только один метакласс под названием Class. Это подразумевало, что методы всех классов были одинаковыми, в частности метод создания новых объектов, т.е. new. Чтобы позволить классам иметь свои собственные методы и свои собственные переменные экземпляра (называемые переменными экземпляра класса, и их не следует путать с переменными класса ), Smalltalk-80 введен для каждого класса. C свой метакласс C class. Это означает, что каждый метакласс фактически является одноэлементным классом.

Поскольку не требуется, чтобы метаклассы вели себя иначе, все метаклассы являются экземплярами только одного класса, называемого Metaclass. Метакласс Metaclass называется Metaclass class который снова является экземпляром класса Metaclass.

В Smalltalk-80 каждый класс (кроме Object) имеет суперкласс . Абстрактным суперклассом всех метаклассов является Class, который описывает общую природу классов.

Иерархия суперклассов для метаклассов аналогична иерархии классов, за исключением класса Object. ВСЕ метаклассы являются подклассами Class, поэтому:

  • Object class superclass == Class.

Подобно сросшимся близнецам , классы и метаклассы рождаются вместе. Metaclass имеет переменную экземпляра thisClass, что указывает на его объединенный класс. Обратите внимание, что обычный браузер классов Smalltalk не отображает метаклассы как отдельные классы. Вместо этого браузер классов позволяет одновременно редактировать класс вместе с его метаклассом.

Имена классов в иерархии метаклассов легко спутать с одноименными понятиями. Например:

  • Object — базовый класс, предоставляющий общие методы для всех объектов; «объект» — это целое число, виджет или Car, и т. д.
  • Class является основой метаклассов, предоставляющей общие методы для всех классов (хотя сам по себе он не является метаклассом); "класс" - это что-то вроде Integer, или Widget, или Car, и т. д.
  • Metaclass предоставляет общие методы для всех метаклассов.

Четыре класса предоставляют возможности для описания новых классов. Их иерархия наследования (от Object) и основные возможности, которые они предоставляют:

Объект — поведение по умолчанию, общее для всех объектов, например доступ к классу.
Поведение — минимальное состояние для компиляции методов и создания/запуска объектов.
ClassDescription ( абстрактный класс ) — имя класса/переменной, комментарии.
Класс - аналогичные, более полные возможности суперклассов.
Метакласс — инициализация переменных класса, сообщения о создании экземпляра

В Рубине

[ редактировать ]

Ruby очищает концепцию метаклассов Smalltalk-80, вводя собственные классы . удаление Metaclass сорт, и (не)переопределение класса карты. Схематически это изменение можно представить следующим образом: [6]

Смоллток-80
Классы
Скрытый
метаклассы
  
Терминал
объекты
Руби
Классы
Собственные классы или
занятия
Собственные классы
из
собственные классы
Терминал
объекты
Собственные классы или
терминальные объекты

Обратите особое внимание на соответствие между неявными метаклассами Smalltalk и собственными классами классов Ruby. Модель собственных классов Ruby делает концепцию неявных метаклассов полностью единообразной: каждый объект x имеет свой собственный мета-объект, называемый собственным классом x , который на один метауровень выше, чем x . Собственные классы «высшего порядка» обычно существуют чисто концептуально – они не содержат никаких методов и не хранят никаких (других) данных в большинстве программ Ruby. [7]

На следующих диаграммах показан пример базовой структуры Smalltalk-80 и Ruby в сравнении. [8] В обоих языках структура состоит из встроенной части, содержащей циклические объекты (т. е. объекты, которые появляются в цикле, образованном комбинацией синих или зеленых ссылок), и пользовательской части, которая имеет четыре явных объекта: классы. A и B и терминальные объекты u и v. Зеленые ссылки показывают отношение наследования дочерний → родительский (с неявным направлением вверх), синие ссылки показывают дополнительное отношение член → контейнер создания экземпляра (синяя ссылка от x указывает на наименее реальный контейнер x , который является начальной точкой для поиск метода при вызове метода для x ). Серые узлы отображают собственные классы (соответственно неявные метаклассы в случае Smalltalk-80).

Смоллток-80   Руби
Неявные метаклассы в Smalltalk-80 — пример структуры Собственные классы в Ruby — пример структуры

Диаграмма справа также дает представление о ленивом вычислении собственных классов в Ruby. v собственный класс объекта может быть оценен (выделен) в результате добавления одноэлементных методов к v.

Согласно методу самоанализа Руби, названному class, класс каждого класса (и каждого собственного класса) равен постоянно Class класс (обозначается c на схеме). Class, и Struct являются единственными классами, экземплярами которых являются классы. [9] [ оспаривается обсуждаем ] Подклассы Class запрещено. Следуя стандартному определению метаклассов, мы можем заключить, что Class и Struct — единственные метаклассы в Ruby. Кажется, это противоречит переписке между Ruby и Smalltalk, поскольку в Smalltalk-80 каждый класс имеет свой собственный метакласс. Расхождение основано на разногласиях между тот class метод самоанализа в Ruby и Smalltalk. Хотя карта x ↦ x. class на терминальных объектах совпадает, отличается ограничением на классы. Как уже говорилось выше, для класса x, выражение Ruby x.class постоянно оценивает Class. В Smalltalk-80, если x является классом, то выражение x class соответствует к Рубину x.singleton_class – который оценивается как собственный класс x.

Диаграмма отношений наследования и экземпляров между классами и метаклассами в Objective-C. Обратите внимание, что Objective-C имеет несколько корневых классов; каждый корневой класс будет иметь отдельную иерархию. На этой диаграмме показана иерархия только для примера корневого класса NSObject. Каждый другой корневой класс будет иметь аналогичную иерархию.

Метаклассы в Objective-C почти такие же, как в Smalltalk-80, что неудивительно, поскольку Objective-C многое заимствует у Smalltalk. Как и в Smalltalk, в Objective-C переменные и методы экземпляра определяются классом объекта. Класс — это объект, следовательно, он является экземпляром метакласса.

Как и в Smalltalk, в Objective-C методы класса — это просто методы, вызываемые для объекта класса, поэтому методы класса класса должны быть определены как методы экземпляра в его метаклассе. Поскольку разные классы могут иметь разные наборы методов класса, каждый класс должен иметь свой отдельный метакласс. Классы и метаклассы всегда создаются парой: среда выполнения имеет функции. objc_allocateClassPair() и objc_registerClassPair() для создания и регистрации пар класс-метакласс соответственно.

Для метаклассов нет названий; однако на указатель на любой объект класса можно ссылаться с помощью универсального типа. Class (аналогично типу id используется для указателя на любой объект).

Поскольку методы класса наследуются посредством наследования, как в Smalltalk, метаклассы должны следовать схеме наследования, параллельной схеме наследования классов (например, если родительским классом класса A является класс B, то родительским классом метакласса A является метакласс B), за исключением корневого класса.

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

Поскольку объекты метакласса не ведут себя по-разному (вы не можете добавлять методы класса для метакласса, поэтому все объекты метакласса имеют одинаковые методы), все они являются экземплярами одного и того же класса — метакласса корневого класса (в отличие от Smalltalk). Таким образом, метакласс корневого класса является экземпляром самого себя. Причина этого в том, что все метаклассы наследуются от корневого класса; следовательно, они должны наследовать методы корневого класса. [10]

Поддержка языков и инструментов

[ редактировать ]

Ниже приведены некоторые из наиболее известных языков программирования , поддерживающих метаклассы.

Некоторые менее распространенные языки, поддерживающие метаклассы, включают OpenJava , OpenC++ , OpenAda , CorbaScript , ObjVLisp , Object-Z , MODEL-K , XOTcl и MELDC . Некоторые из этих языков датируются началом 1990-х годов и представляют академический интерес. [12]

Logtalk , объектно-ориентированное расширение Пролога , также поддерживает метаклассы.

Структура описания ресурсов (RDF) и унифицированный язык моделирования (UML) поддерживают метаклассы.

См. также

[ редактировать ]
  1. ^ Ира Р. Форман и Скотт Дэнфорт (1999). Использование метаклассов в работе . Аддисон-Уэсли. ISBN  0-201-43305-2 .
  2. ^ AloorRavi, Sulekha (2022). Metaprogramming with Python . Birmingham: Packt Publishing.
  3. ^ Программирование IBM Metaclass на Python, части 1. Архивировано 3 сентября 2008 г. на Wayback Machine , 2 и 3.
  4. ^ Форум Artima: Метаклассы в Python 3.0 (часть 1 из 2) (часть 2 из 2)
  5. ^ Дэвид Мерц. «Букварь по программированию метаклассов Python» . ONLamp . Архивировано из оригинала 30 апреля 2003 года . Проверено 28 июня 2006 г.
  6. ^ «Объектная модель Ruby: сравнение со Smalltalk-80» .
  7. ^ Паоло Перротта (2010). Метапрограммирование Ruby . Прагматичная книжная полка. ISBN  978-1-934356-47-0 .
  8. ^ «Членство объектов: основная структура объектной технологии» .
  9. ^ «Структура» . Руби Док . Проверено 1 мая 2015 г.
  10. ^ Какао с любовью: Что такое метакласс в Objective-C?
  11. ^ Херб Саттер . «Метаклассы» (PDF) .
  12. ^ «Реализация примесей в Java с использованием метаклассов» (PDF) . Архивировано из оригинала (PDF) 16 октября 2007 г. Проверено 27 ноября 2007 г.
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 1737d10a9759e7a9dd9f2c0773bd71bf__1719215220
URL1:https://arc.ask3.ru/arc/aa/17/bf/1737d10a9759e7a9dd9f2c0773bd71bf.html
Заголовок, (Title) документа по адресу, URL1:
Metaclass - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)