stringtranslate.com

Метакласс

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

Пример на Python

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

класс  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 f " { self . color } { self . make } { self . model } "     

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

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

class  AttributeInitType ( type ):  def  __call__ ( self ,  * args ,  ** kwargs ): """Создать новый экземпляр."""  # Сначала создадим объект обычным способом по умолчанию.  obj  =  type . __call__ ( self ,  * args ) # Дополнительно, установите атрибуты для нового объекта.  for  name ,  value  in  kwargs . items ():  setattr ( obj ,  name ,  value ) # Возвращаем новый объект.  return  obj

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

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

class  Car ( object ,  metaclass = AttributeInitType ):  @property  def  description ( self )  ->  str : """Вернуть описание этого автомобиля.""" return " " . join ( str ( value ) for value in self . __dict__ . values ​​())       

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

new_car  =  Автомобиль ( марка = 'Toyota' ,  модель = 'Prius' ,  год = 2005 ,  цвет = 'Зеленый' ,  двигатель = 'Гибрид' )

В Smalltalk-80

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

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

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

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

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

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

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

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

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

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

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

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

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

В рубине

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

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

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

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

Согласно методу интроспекции Ruby, называемому 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соответствует выражению Ruby x.singleton_class– которое вычисляется как собственный класс x.

В Objective-C

Диаграмма наследования и отношений экземпляров между классами и метаклассами в 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 , объектно-ориентированное расширение Prolog , также поддерживает метаклассы.

И Resource Description Framework (RDF), и Unified Modeling Language (UML) поддерживают метаклассы.

Смотрите также

Ссылки

  1. ^ Айра Р. Форман и Скотт Дэнфорт (1999). Putting Metaclasses to Work . Addison-Wesley. ISBN 0-201-43305-2.
  2. ^ AloorRavi, Sulekha (2022). Метапрограммирование с Python . Бирмингем: Packt Publishing.
  3. ^ Программирование IBM Metaclass на Python, части 1 Архивировано 03.09.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. Pragmatic Bookshelf. ISBN 978-1-934356-47-0.
  8. ^ «Принадлежность к объектам: основная структура объектной технологии».
  9. ^ "Struct". Ruby Doc . Получено 1 мая 2015 г.
  10. ^ Какао с любовью: Что такое метакласс в Objective-C?
  11. ^ Херб Саттер . «Метаклассы» (PDF) .
  12. ^ "Реализация миксинов в Java с использованием метаклассов" (PDF) . Архивировано из оригинала (PDF) 2007-10-16 . Получено 2007-11-27 .

Внешние ссылки