Эта статья поднимает множество проблем. Пожалуйста, помогите улучшить его или обсудите эти проблемы на странице обсуждения . ( Узнайте, как и когда удалить эти сообщения-шаблоны ) ( Узнайте, как и когда удалить этот шаблон сообщения )
|
В объектно-ориентированном программировании , метаклассом это класс , экземпляры которого являются классами. Так же, как обычный класс определяет поведение определенных объектов, метакласс определяет поведение определенных классов и их экземпляров. Не все объектно-ориентированные языки программирования поддерживают метаклассы. Среди тех, которые это делают, степень, в которой метаклассы могут переопределить любой заданный аспект поведения класса, варьируется. Метаклассы могут быть реализованы, если классы являются первоклассными гражданами , и в этом случае метакласс - это просто объект, который создает классы. У каждого языка есть свой собственный протокол метаобъектов , набор правил, регулирующих взаимодействие объектов, классов и метаклассов. [1]
Пример Python [ править ]
В Python встроенный класс type
- это метакласс. [2] [3] [4] Рассмотрим этот простой класс Python:
class Car : def __init__ ( self , make : str , model : str , year : int , color : str ) -> None : self . make = сделать себя . модель = модель себя . год = год самостоятельно . color = цвет @property def description ( self ): "" "Вернуть описание этой машины." "" return f " { self . color } { self . year } { self . make } { self . model } "
Во время выполнения Car
сам является экземпляром type
. Исходный код Car
класса, показанный выше, не включает такие детали, как размер Car
объектов в байтах , их двоичное расположение в памяти, способ их выделения, то, что __init__
метод автоматически вызывается каждый раз при Car
создании a и т. Д. Эти детали вступают в игру не только при создании нового Car
объекта, но и при каждом Car
доступе к любому атрибуту объекта . В языках без метаклассов эти детали определяются спецификацией языка и не могут быть изменены. В Python метакласс - type
контролирует эти детали Car
поведения. Их можно переопределить, используя другой метакласс вместо type
.
Приведенный выше пример содержит некоторый избыточный код , чтобы сделать с четырьмя атрибутами make
, model
, year
, и color
. Отчасти эту избыточность можно устранить с помощью метакласса. В Python метакласс проще всего определить как подкласс type
.
class AttributeInitType ( type ): def __call__ ( self , * args , ** kwargs ): "" "Создать новый экземпляр." "" # Сначала создайте объект обычным способом по умолчанию. obj = тип . __call__ ( сам , * аргументы ) # Дополнительно установите атрибуты на новый объект. для имени , ценят в kwargs . items (): setattr ( объект , имя , значение ) # Вернуть новый объект. вернуть объект
Этот метакласс отменяет только создание объекта. Все остальные аспекты поведения классов и объектов по-прежнему обрабатываются type
.
Теперь класс Car
можно переписать для использования этого метакласса. В Python 3 это делается путем предоставления "аргумента ключевого слова" metaclass
определению класса:
class Car ( object , metaclass = AttributeInitType ): @property def description ( self ): "" "Вернуть описание этой машины." "" return "" . join ( str ( значение ) для значения в self . __dict__ . values ())
Результирующий объект Car
может быть создан как обычно, но может содержать любое количество аргументов ключевого слова:
new_car = Автомобиль ( марка = 'Toyota' , модель = 'Prius' , год = 2005 , цвет = 'Зеленый' , двигатель = 'Гибрид' )
В Smalltalk-80 [ править ]
В этом разделе не процитировать любые источники . ( Октябрь 2013 г. ) ( Узнайте, как и когда удалить этот шаблон сообщения ) |
В 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
. Все метаклассы являются подклассами класса.
В ранних версиях 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) и основные возможности, которые они предоставляют:
- Объект - поведение по умолчанию, общее для всех объектов, например доступ к классу
- Behavior - минимальное состояние для компиляции методов и создания / запуска объектов
- ClassDescription ( абстрактный класс ) - имя класса / переменной, комментарии
- Класс - аналогичные, более широкие возможности суперклассов
- Метакласс - инициализация переменных класса, сообщения о создании экземпляра
- ClassDescription ( абстрактный класс ) - имя класса / переменной, комментарии
- Behavior - минимальное состояние для компиляции методов и создания / запуска объектов
В Ruby [ править ]
Ruby очищает концепцию метаклассов в Smalltalk-80, вводя собственные классы , удаляя Metaclass
класс и ( отменяя ) переопределение класса map. Это изменение можно схематически представить следующим образом: [5]
| → |
|
Обратите внимание на соответствие между неявными метаклассами Smalltalk и собственными классами классов Ruby. The Ruby eigenclass модель делает концепцию неявного метаклассами полностью однородным: каждый объект х имеет свой собственный мета-объект, называемый eigenclass из х , который является один мета-уровень выше , чем х . Собственные классы «более высокого порядка» обычно существуют чисто концептуально - они не содержат никаких методов и не хранят никаких (других) данных в большинстве программ Ruby. [6]
На следующих диаграммах показано сравнение типовой структуры ядра Smalltalk-80 и Ruby. [7]
В обоих языках структура состоит из встроенной части, которая содержит круглые объекты (т.е. объекты, которые появляются в цикле, образованном комбинацией синих или зеленых ссылок), и пользовательской части, которая имеет четыре явных объекта: классы A
и B
и терминальные объекты u
и v
. Зеленые ссылки показывают отношение наследования дочерний → родительский (с неявным направлением вверх), синие ссылки показывают дополнительное отношение член → контейнер создания экземпляра (синяя ссылка от x указывает на наименее актуальный контейнер x, который является начальной точкой для поиск метода, когда метод вызывается на x). Серые узлы отображают собственные классы (соответственно неявные метаклассы в случае Smalltalk-80).
Smalltalk-80 | Рубин | |
На диаграмме справа также показано ленивое вычисление собственных классов в Ruby. Собственный v
класс объекта может быть оценен (выделен) в результате добавления одноэлементных методов в v
.
Согласно названному методу интроспекции Ruby class
, класс каждого класса (и каждого собственного класса) постоянно является Class
классом (обозначенным c
на схеме как). Class
, и Struct
являются единственными классами, у которых есть классы как экземпляры. [8] [ оспаривается ] Создание подклассов Class
запрещено. Следуя стандартному определению метаклассов, мы можем сделать вывод, что Class
и Struct
являются единственными метаклассами в Ruby. Кажется, это противоречит соответствию между Ruby и Smalltalk, поскольку в Smalltalk-80 каждый класс имеет свой собственный метакласс. Несоответствие основано на разногласиях между class
методом интроспекции в Ruby и Smalltalk. Пока картах ↦ х. class
на терминальных объектах совпадает, отличается ограничением на классы. Как уже упоминалось выше, для класса x
выражение Ruby x.class
постоянно оценивается как Class
. В Smalltalk-80, если x
это класс, тогда выражение x class
соответствует Ruby, x.singleton_class
которое оценивается как собственный класс x
.
В Objective-C [ править ]
Этот раздел требует дополнительных ссылок для проверки . Октябрь 2013 г. ) ( Узнайте, как и когда удалить этот шаблон сообщения ) ( |
Тон или стиль этого раздела могут не отражать энциклопедический тон, используемый в Википедии . Сентябрь 2013 г. ) ( Узнайте, как и когда удалить этот шаблон сообщения ) ( |
Метаклассы в 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
использующего структуру Какао ). Это гарантирует, что все объекты класса в конечном итоге являются экземплярами корневого класса, так что вы можете использовать методы экземпляра корневого класса, обычно полезные служебные методы для объектов, на самих объектах класса.
Поскольку объекты метакласса не ведут себя по-разному (вы не можете добавлять методы класса для метакласса, поэтому все объекты метакласса имеют одинаковые методы), все они являются экземплярами одного и того же класса - метакласса корневого класса (в отличие от Smalltalk). Таким образом, метакласс корневого класса является экземпляром самого себя. Причина этого в том, что все метаклассы наследуются от корневого класса; следовательно, они должны наследовать методы класса корневого класса. [9]
Поддержка языков и инструментов [ править ]
Ниже приведены некоторые из наиболее известных языков программирования , поддерживающих метаклассы.
- Common Lisp через CLOS
- Delphi и другие версии Object Pascal, на которые он повлиял
- Groovy
- Цель-C
- Python
- Perl через прагму метакласса, а также Moose
- Рубин
- Болтовня
- C ++ (планируется для C ++ 23 ) [10]
Некоторые менее распространенные языки, поддерживающие метаклассы, включают OpenJava , OpenC ++ , OpenAda , CorbaScript , ObjVLisp , Object-Z , MODEL-K , XOTcl и MELDC . Некоторые из этих языков появились в начале 1990-х годов и представляют академический интерес. [11]
Logtalk , объектно-ориентированное расширение Prolog , также поддерживает метаклассы.
Платформа описания ресурсов (RDF) и унифицированный язык моделирования (UML) поддерживают метаклассы.
См. Также [ править ]
- Метамодель
- Метапрограммирование
- Метаобъект
- Добрый (теория типов)
- Отражение
- Динамизм
- Шаблон адаптера
- Метакласс (семантическая сеть)
- Что такое метакласс?
Ссылки [ править ]
- ↑ Ира Р. Форман и Скотт Дэнфорт (1999). Запуск метаклассов в работу . ISBN 0-201-43305-2.
- ^ Программирование IBM Metaclass на Python, части 1 Архивировано 3 сентября2008 г. на Wayback Machine , 2 и 3
- ^ Форум Artima: Метаклассы в Python 3.0 (часть 1 из 2) (часть 2 из 2)
- ^ Дэвид Мертц. "Учебник по программированию метаклассов Python" . ONLamp . Архивировано из оригинала на 30 апреля 2003 года . Проверено 28 июня 2006 года .
- ^ «Объектная модель Ruby: сравнение с Smalltalk-80» .
- ^ Паоло Перротта (2010). Метапрограммирование Ruby . Прагматическая книжная полка. ISBN 978-1-934356-47-0.
- ^ «Членство в объектах: основная структура объектной технологии» .
- ^ "Struct" . Руби Док . Дата обращения 1 мая 2015 .
- ^ Какао с любовью: что такое мета-класс в Objective-C?
- ^ Херб Саттер . «Метаклассы» (PDF) .
- ^ «Реализация миксинов на Java с использованием метаклассов» (PDF) . Архивировано из оригинального (PDF) 16 октября 2007 года . Проверено 27 ноября 2007 .