В Python, что такое метаклассы и для чего мы их используем?
источник
В Python, что такое метаклассы и для чего мы их используем?
Метакласс - это класс класса. Класс определяет, как ведет себя экземпляр класса (то есть объект), а метакласс определяет поведение класса. Класс является экземпляром метакласса.
В то время как в Python вы можете использовать произвольные вызываемые элементы для метаклассов (как показано на Jerub ), лучший подход состоит в том, чтобы сделать его самим классом. type
это обычный метакласс в Python. type
сам по себе класс, и это его собственный тип. Вы не сможете воссоздать что-то вроде type
чисто в Python, но Python немного обманывает. Чтобы создать свой собственный метакласс в Python, вы действительно хотите создать подкласс type
.
Метакласс чаще всего используется как фабрика классов. Когда вы создаете объект, вызывая класс, Python создает новый класс (когда он выполняет оператор 'class'), вызывая метакласс. В сочетании с обычным __init__
и __new__
методами метаклассы, таким образом, позволяют создавать «дополнительные вещи» при создании класса, такие как регистрация нового класса в некотором реестре или замена класса чем-то другим полностью.
Когда class
инструкция выполняется, Python сначала выполняет тело class
инструкции как обычный блок кода. Результирующее пространство имен (dict) содержит атрибуты будущего класса. Метакласс определяется путем просмотра базовых классов будущего класса (метаклассы наследуются), __metaclass__
атрибута будущего класса (если есть) или __metaclass__
глобальной переменной. Затем метакласс вызывается с именем, основами и атрибутами класса, чтобы создать его экземпляр.
Тем не менее, метаклассы фактически определяют тип класса, а не просто фабрику для него, так что вы можете сделать с ними гораздо больше. Например, вы можете определить нормальные методы в метаклассе. Эти метакласс-методы похожи на методы класса в том смысле, что их можно вызывать в классе без экземпляра, но они также не похожи на методы класса в том смысле, что их нельзя вызывать в экземпляре класса. type.__subclasses__()
пример метода в type
метаклассе Вы также можете определить обычные «магические» методы, например __add__
, __iter__
и __getattr__
, чтобы реализовать или изменить поведение класса.
Вот агрегированный пример кусочков:
def make_hook(f):
"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook = 1
return f
class MyType(type):
def __new__(mcls, name, bases, attrs):
if name.startswith('None'):
return None
# Go over attributes and see if they should be renamed.
newattrs = {}
for attrname, attrvalue in attrs.iteritems():
if getattr(attrvalue, 'is_hook', 0):
newattrs['__%s__' % attrname] = attrvalue
else:
newattrs[attrname] = attrvalue
return super(MyType, mcls).__new__(mcls, name, bases, newattrs)
def __init__(self, name, bases, attrs):
super(MyType, self).__init__(name, bases, attrs)
# classregistry.register(self, self.interfaces)
print "Would register class %s now." % self
def __add__(self, other):
class AutoClass(self, other):
pass
return AutoClass
# Alternatively, to autogenerate the classname as well as the class:
# return type(self.__name__ + other.__name__, (self, other), {})
def unregister(self):
# classregistry.unregister(self)
print "Would unregister class %s now." % self
class MyObject:
__metaclass__ = MyType
class NoneSample(MyObject):
pass
# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)
class Example(MyObject):
def __init__(self, value):
self.value = value
@make_hook
def add(self, other):
return self.__class__(self.value + other.value)
# Will unregister the class
Example.unregister()
inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()
print inst + inst
class Sibling(MyObject):
pass
ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__
class A(type):pass<NEWLINE>class B(type,metaclass=A):pass<NEWLINE>b.__class__ = b
__metaclass__
не поддерживается в Python 3. В Python 3 используйтеclass MyObject(metaclass=MyType)
, см. Python.org/dev/peps/pep-3115 и ответ ниже.Классы как объекты
Прежде чем разбираться в метаклассах, вам нужно освоить классы на Python. И у Python очень своеобразное представление о том, что такое классы, заимствованные из языка Smalltalk.
В большинстве языков классы - это просто фрагменты кода, которые описывают, как создать объект. Это также верно в Python:
Но классы больше, чем в Python. Классы тоже объекты.
Да, объекты.
Как только вы используете ключевое слово
class
, Python выполняет его и создает ОБЪЕКТ. Инструкциясоздает в памяти объект с именем «ObjectCreator».
Этот объект (класс) сам по себе способен создавать объекты (экземпляры), и именно поэтому он является классом .
Но все же, это объект, и поэтому:
например:
Создание классов динамически
Поскольку классы являются объектами, вы можете создавать их на лету, как и любой объект.
Во-первых, вы можете создать класс в функции, используя
class
:Но это не так динамично, так как вам все равно придется писать весь класс самостоятельно.
Поскольку классы являются объектами, они должны быть сгенерированы чем-то.
Когда вы используете
class
ключевое слово, Python создает этот объект автоматически. Но, как и большинство вещей в Python, он дает вам возможность сделать это вручную.Помните функцию
type
? Старая добрая функция, которая позволяет узнать тип объекта:Ну,
type
обладает совершенно другой способностью, он также может создавать классы на лету.type
может взять описание класса в качестве параметров и вернуть класс.(Я знаю, что глупо, что одна и та же функция может иметь два совершенно разных использования в зависимости от параметров, которые вы передаете ей. Это проблема из-за обратной совместимости в Python)
type
работает так:Куда:
name
: название классаbases
: кортеж родительского класса (для наследования может быть пустым)attrs
: словарь, содержащий имена и значения атрибутовнапример:
можно создать вручную таким образом:
Вы заметите, что мы используем «MyShinyClass» в качестве имени класса и в качестве переменной для хранения ссылки на класс. Они могут быть разными, но нет причин усложнять вещи.
type
принимает словарь для определения атрибутов класса. Так:Можно перевести на:
И используется как обычный класс:
И, конечно, вы можете наследовать от него, так что:
было бы:
В конце концов вы захотите добавить методы в ваш класс. Просто определите функцию с правильной подписью и назначьте ее в качестве атрибута.
И вы можете добавить еще больше методов после динамического создания класса, точно так же, как добавление методов в нормально созданный объект класса.
Вы видите, куда мы идем: в Python классы являются объектами, и вы можете динамически создавать классы на лету.
Это то, что делает Python, когда вы используете ключевое слово
class
, и это делается с помощью метакласса.Что такое метаклассы (наконец)
Метаклассы - это «материал», который создает классы.
Вы определяете классы для создания объектов, верно?
Но мы узнали, что классы Python являются объектами.
Ну, метаклассы - это то, что создает эти объекты. Это классы классов, вы можете изобразить их следующим образом:
Вы видели, что
type
позволяет вам сделать что-то вроде этого:Это потому, что функция
type
на самом деле является метаклассом.type
является метаклассом, который Python использует для создания всех классов за сценой.Теперь вы задаетесь вопросом, какого чёрта это написано в нижнем регистре, а нет
Type
?Ну, я думаю, что это вопрос согласованности с
str
классом, который создает строковые объекты, иint
классом, который создает целочисленные объекты.type
это просто класс, который создает объекты класса.Вы видите это, проверив
__class__
атрибут.Все, и я имею в виду все, является объектом в Python. Это включает в себя целые, строки, функции и классы. Все они объекты. И все они были созданы из класса:
Теперь, что это
__class__
какой - либо__class__
?Итак, метакласс - это просто материал, который создает объекты класса.
Вы можете назвать это «фабрикой классов», если хотите.
type
Это встроенный метакласс, который использует Python, но, конечно, вы можете создать свой собственный метакласс.__metaclass__
атрибутВ Python 2 вы можете добавить
__metaclass__
атрибут при написании класса (см. Следующий раздел о синтаксисе Python 3):Если вы это сделаете, Python будет использовать метакласс для создания класса
Foo
.Осторожно, это сложно.
class Foo(object)
Сначала вы пишете , но объект классаFoo
еще не создан в памяти.Python будет искать
__metaclass__
в определении класса. Если он найдет его, он будет использовать его для создания класса объектаFoo
. Если это не так, он будет использоватьtype
для создания класса.Прочитайте это несколько раз.
Когда вы делаете:
Python делает следующее:
Есть ли
__metaclass__
атрибут вFoo
?Если да, создайте в памяти объект класса (я сказал объект класса, оставайтесь со мной здесь), с именем
Foo
, используя то, что в__metaclass__
.Если Python не может найти
__metaclass__
, он будет искать__metaclass__
на уровне MODULE и попытаться сделать то же самое (но только для классов, которые ничего не наследуют, в основном классы старого стиля).Затем, если он вообще не может его найти
__metaclass__
, он будет использоватьBar
собственный метакласс (первого родителя) (который может быть по умолчаниюtype
) для создания объекта класса.Будьте осторожны, что
__metaclass__
атрибут не будет наследоваться, метакласс parent (Bar.__class__
) будет. ЕслиBar
используется__metaclass__
атрибут, созданныйBar
сtype()
(и неtype.__new__()
), подклассы не будут наследовать это поведение.Теперь большой вопрос, что вы можете вставить
__metaclass__
?Ответ: что-то, что может создать класс.
А что может создать класс?
type
или все, что подклассы или использует его.Метаклассы в Python 3
Синтаксис для установки метакласса был изменен в Python 3:
т.е.
__metaclass__
атрибут больше не используется, в пользу ключевого аргумента в списке базовых классов.Поведение метаклассов, однако, остается в основном таким же .
Одна вещь, добавленная к метаклассам в Python 3, заключается в том, что вы также можете передавать атрибуты как аргументы-ключевые слова в метакласс, например, так:
Прочитайте раздел ниже, чтобы узнать, как Python справляется с этим.
Пользовательские метаклассы
Основное назначение метакласса - автоматическое изменение класса при его создании.
Вы обычно делаете это для API, где вы хотите создать классы, соответствующие текущему контексту.
Представьте себе глупый пример, когда вы решаете, что все классы в вашем модуле должны иметь свои атрибуты, написанные в верхнем регистре. Есть несколько способов сделать это, но один из них - установить
__metaclass__
на уровне модуля.Таким образом, все классы этого модуля будут созданы с использованием этого метакласса, и нам просто нужно указать метаклассу, чтобы все атрибуты были заглавными.
К счастью, на
__metaclass__
самом деле это может быть любой вызываемый объект, он не должен быть формальным классом (я знаю, что-то с именем «class» в названии не обязательно должно быть классом, поймите, что ... но это полезно).Итак, начнем с простого примера с использования функции.
Давайте проверим:
Теперь давайте сделаем точно так же, но используя реальный класс для метакласса:
Давайте перепишем вышесказанное, но теперь с более короткими и реалистичными именами переменных, теперь мы знаем, что они означают:
Возможно, вы заметили дополнительный аргумент
cls
. В этом нет ничего особенного:__new__
всегда получает класс, в котором он определен, в качестве первого параметра. Точно так же, как уself
обычных методов, которые получают экземпляр в качестве первого параметра или определяющий класс для методов класса.Но это не правильный ООП. Мы звоним
type
напрямую, и мы не переопределяем или не звоним родителям__new__
. Давайте сделаем это вместо этого:Мы можем сделать его еще чище, используя
super
, что облегчит наследование (потому что да, у вас могут быть метаклассы, наследование от метаклассов, наследование от типа):Да, и в Python 3, если вы делаете этот вызов с аргументами ключевых слов, например:
Это переводит это в метакласс, чтобы использовать это:
Вот и все. В метаклассах больше ничего нет.
Причиной сложности кода с использованием метаклассов является не метаклассы, а то, что вы обычно используете метаклассы для скрученных вещей, полагаясь на интроспекцию, манипулирование наследованием, такие переменные
__dict__
и т. Д.Действительно, метаклассы особенно полезны для создания чёрной магии и, следовательно, сложных вещей. Но сами по себе они просты
Почему вы используете классы метаклассов вместо функций?
Так как
__metaclass__
может принять любой вызываемый объект, зачем вам использовать класс, поскольку он явно более сложный?Для этого есть несколько причин:
UpperAttrMetaclass(type)
, вы знаете, что последует__new__
,__init__
и__call__
. Что позволит вам делать разные вещи. Даже если обычно вы можете делать все это__new__
, некоторым людям просто удобнее пользоваться__init__
.Почему вы используете метаклассы?
Теперь большой вопрос. Зачем вам использовать какую-то неясную функцию, склонную к ошибкам?
Ну, обычно вы этого не делаете:
Питон Гуру Тим Питерс
Основным вариантом использования метакласса является создание API. Типичным примером этого является Django ORM. Это позволяет вам определить что-то вроде этого:
Но если вы сделаете это:
Это не вернет
IntegerField
объект. Он вернетint
, и может даже взять его непосредственно из базы данных.Это возможно, потому что
models.Model
определяет__metaclass__
и использует некоторую магию, которая превратитPerson
только что заданные вами простые выражения в сложный крюк для поля базы данных.Django делает что-то сложное простым, предоставляя простой API и используя метаклассы, воссоздавая код из этого API для реальной работы за кулисами.
Последнее слово
Во-первых, вы знаете, что классы - это объекты, которые могут создавать экземпляры.
Ну, на самом деле, классы сами по себе являются примерами. Метаклассов.
В Python все является объектом, и все они являются экземплярами классов или экземплярами метаклассов.
За исключением
type
.type
на самом деле его собственный метакласс. Это не то, что вы могли бы воспроизвести на чистом Python, и это делается путем обмана на уровне реализации.Во-вторых, метаклассы сложны. Возможно, вы не захотите использовать их для очень простых изменений класса. Вы можете изменить классы, используя два разных метода:
В 99% случаев вам нужно изменить класс, лучше использовать их.
Но в 98% случаев вам вообще не нужно менять класс.
источник
models.Model
он не использует,__metaclass__
а скорееclass Model(metaclass=ModelBase):
ссылается наModelBase
класс, который затем использует магию вышеупомянутого метакласса. Отличный пост! Вот источник Django: github.com/django/django/blob/master/django/db/models/…__metaclass__
атрибут не был унаследован, метакласс родительского (Bar.__class__
) будет. ЕслиBar
использовал__metaclass__
атрибут, созданныйBar
сtype()
(и неtype.__new__()
), подклассы не будут наследовать такое поведение. >> - Не могли бы вы / кто-нибудь объяснить, пожалуйста, немного глубже этот отрывок?Now you wonder why the heck is it written in lowercase, and not Type?
- хорошо, потому что это реализовано в C - это та же самая причина, по которой defaultdict является строчными, в то время как OrderedDict (в python 2) является обычным CamelCaseОбратите внимание, что этот ответ для Python 2.x, как он был написан в 2008 году, метаклассы немного отличаются в 3.x.
Метаклассы - это секретный соус, который заставляет работать «класс». Метакласс по умолчанию для нового объекта стиля называется «тип».
Метаклассы занимают 3 аргумента. « имя », « основания » и « дикт »
Здесь начинается секрет. Ищите, откуда взято имя, основания и диктат в этом примере определения класса.
Давайте определим метакласс, который продемонстрирует, как class: называет его.
И теперь, пример, который на самом деле что-то значит, это автоматически сделает переменные в списке «атрибуты» установленными в классе и установит None.
Обратите внимание, что магическое поведение,
Initialised
получаемое при наличии метаклассаinit_attributes
, не передается в подклассInitialised
.Вот еще более конкретный пример, показывающий, как вы можете создать подкласс 'type' для создания метакласса, который выполняет действие при создании класса. Это довольно сложно:
источник
Другие объясняли, как работают метаклассы и как они вписываются в систему типов Python. Вот пример того, для чего они могут быть использованы. В рамках тестирования, который я написал, я хотел отслеживать порядок, в котором были определены классы, чтобы впоследствии я мог их создать в этом порядке. Я нашел, что проще всего сделать это с помощью метакласса.
Все, что является подклассом,
MyType
затем получает атрибут класса,_order
который записывает порядок, в котором классы были определены.источник
__init__(self)
говоритtype(self)._order = MyBase.counter; MyBase.counter += 1
?Одно из применений метаклассов - автоматическое добавление новых свойств и методов в экземпляр.
Например, если вы посмотрите на модели Django , их определение выглядит немного запутанным. Похоже, вы определяете только свойства класса:
Однако во время выполнения объекты Person заполняются всевозможными полезными методами. Посмотрите источник для некоторой удивительной метаклассерии.
источник
Я думаю, что введение ONLamp в программирование метаклассов хорошо написано и дает действительно хорошее введение в тему, хотя ему уже несколько лет.
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (архивируется по адресу https://web.archive.org/web/20080206005253/http://www.onlamp. ком / паб / а / питон / 2003/04/17 / metaclasses.html )
Вкратце: класс - это план для создания экземпляра, метакласс - это план для создания класса. Легко видеть, что в классах Python должны быть объекты первого класса, чтобы включить это поведение.
Сам я никогда не писал, но я думаю, что одно из самых хороших применений метаклассов можно увидеть в структуре Django . Классы моделей используют метаклассовый подход, чтобы включить декларативный стиль написания новых моделей или классов форм. Пока метакласс создает класс, все члены получают возможность настраивать сам класс.
Осталось сказать следующее: если вы не знаете, что такое метаклассы, вероятность того, что они вам не понадобятся, составляет 99%.
источник
TLDR: метакласс создает и определяет поведение для класса так же, как класс создает и определяет поведение для экземпляра.
псевдокод:
Выше должно выглядеть знакомо. Ну откуда же это
Class
? Это экземпляр метакласса (также псевдокода):В реальном коде мы можем передать метакласс по умолчанию
type
, все, что нам нужно для создания экземпляра класса, и мы получаем класс:Говоря по-другому
Класс относится к экземпляру, а метакласс - к классу.
Когда мы создаем экземпляр объекта, мы получаем экземпляр:
Аналогично, когда мы явно определяем класс с метаклассом по умолчанию
type
, мы создаем его экземпляр:Другими словами, класс является экземпляром метакласса:
Иными словами, метакласс - это класс класса.
Когда вы пишете определение класса и Python выполняет его, он использует метакласс для создания экземпляра объекта класса (который, в свою очередь, будет использоваться для создания экземпляров этого класса).
Так же, как мы можем использовать определения классов, чтобы изменить поведение пользовательских объектов, мы можем использовать определение класса метакласса, чтобы изменить поведение объекта класса.
Для чего они могут быть использованы? Из документов :
Тем не менее, пользователям обычно рекомендуется избегать использования метаклассов, если в этом нет крайней необходимости.
Вы используете метакласс каждый раз, когда создаете класс:
Когда вы пишете определение класса, например, как это,
Вы создаете объект класса.
Это то же самое, что функциональный вызов
type
с соответствующими аргументами и присвоение результата переменной с таким именем:Обратите внимание, что некоторые вещи автоматически добавляются
__dict__
в пространство имен:Метаклассом объекта , который мы создали, в обоих случаях это
type
.(Побочное примечание о содержании класса
__dict__
:__module__
есть , потому что классы должны знать , где они определены, а__dict__
и__weakref__
там , потому что мы не определяем ,__slots__
- если мы определим__slots__
, мы немного сэкономить пространство в случаях, когда мы можем запретить__dict__
и__weakref__
исключив их. Например:... но я отвлекся.)
Мы можем расширить
type
как любое другое определение класса:Вот
__repr__
классы по умолчанию :Одна из самых ценных вещей, которые мы можем сделать по умолчанию при написании объекта Python, - это обеспечить его хорошим качеством
__repr__
. Когда мы звоним,help(repr)
мы узнаем, что есть хороший тест для,__repr__
который также требует теста на равенство -obj == eval(repr(obj))
. Следующая простая реализация__repr__
и__eq__
для экземпляров класса нашего класса типов предоставляет нам демонстрацию, которая может улучшить стандартные__repr__
классы:Так что теперь, когда мы создаем объект с этим метаклассом,
__repr__
отображение в командной строке обеспечивает гораздо менее уродливый вид, чем по умолчанию:С хорошим
__repr__
определением для экземпляра класса у нас есть более сильная способность отлаживать наш код. Тем не менее, дальнейшая проверка с использованиемeval(repr(Class))
маловероятна (так как функции было бы довольно невозможно оценить по умолчанию).__repr__
).Ожидаемое использование:
__prepare__
пространство именЕсли, например, мы хотим знать, в каком порядке создаются методы класса, мы можем предоставить упорядоченный dict в качестве пространства имен класса. Мы сделаем это с помощью
__prepare__
которого возвращает dict пространства имен для класса, если он реализован в Python 3 :И использование:
И теперь у нас есть запись порядка, в котором были созданы эти методы (и другие атрибуты класса):
Обратите внимание, этот пример был адаптирован из документации - новый enum в стандартной библиотеке делает .
Итак, мы создали экземпляр метакласса, создав класс. Мы также можем обращаться с метаклассом так же, как и с любым другим классом. У него есть порядок разрешения метода:
И он имеет приблизительно правильный результат
repr
(который мы больше не можем оценить, если не сможем найти способ представить наши функции.):источник
Обновление Python 3
На данный момент есть два ключевых метода в метаклассе:
__prepare__
, а также__new__
__prepare__
позволяет вам предоставить пользовательское отображение (такое какOrderedDict
), которое будет использоваться в качестве пространства имен во время создания класса. Вы должны вернуть экземпляр любого пространства имен, которое вы выберете. Если вы не реализуете__prepare__
нормальныйdict
.__new__
отвечает за фактическое создание / модификацию финального класса.Метаклассу «голые кости», «ничего не делать» хотелось бы:
Простой пример:
Скажем, вы хотите, чтобы на ваших атрибутах выполнялся простой проверочный код - как будто он всегда должен быть
int
илиstr
. Без метакласса ваш класс будет выглядеть примерно так:Как видите, вы должны повторить имя атрибута дважды. Это делает возможным опечатки наряду с раздражающими ошибками.
Простой метакласс может решить эту проблему:
Вот как будет выглядеть метакласс (не используется,
__prepare__
поскольку он не нужен):Примерный прогон:
производит:
Примечание . Этот пример достаточно прост, его также можно было бы выполнить с помощью декоратора классов, но, вероятно, реальный метакласс сделал бы гораздо больше.
Класс ValidateType для справки:
источник
__set_name__(cls, name)
в дескрипторе (ValidateType
), чтобы установить имя в дескрипторе (self.name
и в этом случае такжеself.attr
). Это было добавлено, чтобы не приходилось погружаться в метаклассы для этого конкретного общего случая использования (см. PEP 487).Роль метода метакласса
__call__()
при создании экземпляра классаЕсли вы занимались программированием на Python более нескольких месяцев, вы в конечном итоге натолкнетесь на код, который выглядит следующим образом:
Последнее возможно, когда вы реализуете
__call__()
магический метод в классе.__call__()
Метод вызывается , когда экземпляр класса используется в качестве вызываемого. Но, как мы видели из предыдущих ответов, сам класс является экземпляром метакласса, поэтому, когда мы используем класс в качестве вызываемого (то есть, когда мы создаем его экземпляр), мы фактически вызываем__call__()
метод его метакласса . На данный момент большинство программистов на Python немного смущены, потому что им сказали, что при создании такого экземпляраinstance = SomeClass()
вы вызываете его__init__()
метод. Кто-то, кто вырыл немного глубже, знает это прежде, чем__init__()
есть__new__()
. Что ж, сегодня открывается еще один слой правды, прежде__new__()
чем появится метакласс »__call__()
.Давайте изучим цепочку вызовов метода с точки зрения создания экземпляра класса.
Это метакласс, который регистрирует ровно момент до того, как экземпляр создан, и в тот момент, когда он собирается его вернуть.
Это класс, который использует этот метакласс
А теперь давайте создадим экземпляр
Class_1
Обратите внимание, что приведенный выше код на самом деле ничего не делает, кроме регистрации задач. Каждый метод делегирует фактическую работу реализации его родителя, сохраняя поведение по умолчанию. Поскольку
type
этоMeta_1
родительский класс (type
являющийся родительским метаклассом по умолчанию) и рассматривающий последовательность упорядочения вышеприведенных выходных данных, теперь мы имеем представление о том, какой должна быть псевдо-реализацияtype.__call__()
:Мы видим, что метод метакласса
__call__()
вызывается первым. Затем он делегирует создание экземпляра__new__()
методу класса и инициализацию экземпляру__init__()
. Это также тот, который в конечном итоге возвращает экземпляр.Из вышесказанного вытекает , что метаклассом
__call__()
также предоставляется возможность решить , стоит ли вызовClass_1.__new__()
или вClass_1.__init__()
конечном итоге будет. За время своего выполнения он мог фактически вернуть объект, который не был затронут ни одним из этих методов. Возьмем для примера такой подход к шаблону синглтона:Давайте посмотрим, что происходит при неоднократных попытках создать объект типа
Class_2
источник
Метакласс - это класс, который сообщает, как (какой-то) другой класс должен быть создан.
Это тот случай, когда я рассматривал метакласс как решение своей проблемы: у меня была действительно сложная проблема, которая, возможно, могла быть решена по-другому, но я решил решить ее с помощью метакласса. Из-за сложности, это один из немногих написанных мной модулей, где комментарии в модуле превосходят объем написанного кода. Вот...
источник
Версия tl; dr
type(obj)
Функция получает вас тип объекта.type()
Класса является его метаклассом .Чтобы использовать метакласс:
type
это свой собственный метакласс. Класс класса является метаклассом - тело класса - это аргументы, передаваемые метаклассу, который используется для создания класса.Здесь вы можете прочитать о том, как использовать метаклассы для настройки построения классов.
источник
type
на самом делеmetaclass
класс, который создает другие классы. Большинство из нихmetaclass
являются подклассамиtype
.metaclass
Принимаетnew
класс в качестве первого аргумента и обеспечить доступ к объекту класса с деталями , как указано ниже:Note:
Обратите внимание, что класс не был создан в любое время; простой акт создания класса запускает выполнение
metaclass
.источник
Классы Python сами являются объектами - как, например, - их метакласса.
Метакласс по умолчанию, который применяется, когда вы определяете классы как:
метакласс используется для применения некоторого правила ко всему набору классов. Например, предположим, что вы создаете ORM для доступа к базе данных, и вы хотите, чтобы записи из каждой таблицы относились к классу, сопоставленному с этой таблицей (на основе полей, бизнес-правил и т. Д.), Возможное использование метакласса например, логика пула соединений, которая является общей для всех классов записей из всех таблиц. Другое использование - логика для поддержки внешних ключей, которая включает в себя несколько классов записей.
когда вы определяете метакласс, вы подклассируете тип и можете переопределить следующие магические методы для вставки вашей логики.
во всяком случае, эти два наиболее часто используемые крючки. метаклассирование является мощным, и выше не далеко и исчерпывающий список применений для метаклассирования.
источник
Функция type () может возвращать тип объекта или создавать новый тип,
например, мы можем создать класс Hi с функцией type (), и нам не нужно использовать этот способ с классом Hi (object):
Помимо использования type () для динамического создания классов, вы можете управлять поведением создания класса и использовать метакласс.
Согласно объектной модели Python, класс является объектом, поэтому класс должен быть экземпляром другого определенного класса. По умолчанию класс Python является экземпляром класса type. То есть тип является метаклассом большинства встроенных классов и метаклассом пользовательских классов.
Магия вступит в силу, когда мы передадим аргументы ключевого слова в метаклассе, он указывает интерпретатору Python для создания CustomList через ListMetaclass. new (), на этом этапе мы можем изменить определение класса, например, добавить новый метод и затем вернуть исправленное определение.
источник
В дополнение к опубликованным ответам я могу сказать, что a
metaclass
определяет поведение класса. Таким образом, вы можете явно установить свой метакласс. Всякий раз, когда Python получает ключевое слово,class
он начинает поискmetaclass
. Если он не найден - тип метакласса по умолчанию используется для создания объекта класса. Используя__metaclass__
атрибут, вы можете установитьmetaclass
свой класс:Он выдаст вывод примерно так:
И, конечно же, вы можете создать свой собственный
metaclass
чтобы определить поведение любого класса, созданного с использованием вашего класса.Для этого ваш
metaclass
класс типов по умолчанию должен быть унаследован, так как он является основнымmetaclass
:Выход будет:
источник
В объектно-ориентированном программировании метакласс - это класс, экземплярами которого являются классы. Так же, как обычный класс определяет поведение определенных объектов, метакласс определяет поведение определенного класса и его экземпляров. Термин метакласс просто означает нечто, используемое для создания классов. Другими словами, это класс класса. Метакласс используется для создания класса, поэтому, подобно объекту, являющемуся экземпляром класса, класс является экземпляром метакласса. В Python классы также считаются объектами.
источник
Вот еще один пример того, для чего он может быть использован:
metaclass
для изменения функции своего экземпляра (класса).Он
metaclass
мощный, есть много вещей (например, магия обезьян), которые вы можете сделать с ним, но будьте осторожны, это может быть известно только вам.источник
Класс в Python - это объект, и, как и любой другой объект, это экземпляр «чего-то». Это «что-то» - это то, что называется метаклассом. Этот метакласс является особым типом класса, который создает объекты другого класса. Следовательно, метакласс отвечает за создание новых классов. Это позволяет программисту настроить способ генерации классов.
Для создания метакласса обычно выполняется переопределение методов new () и init (). new () может быть переопределен, чтобы изменить способ создания объектов, в то время как init () может быть переопределен, чтобы изменить способ инициализации объекта. Метакласс может быть создан несколькими способами. Одним из способов является использование функции type (). Функция type () при вызове с 3 параметрами создает метакласс. Параметры: -
Другой способ создания метакласса состоит из ключевого слова metaclass. Определите метакласс как простой класс. В параметрах унаследованного класса передайте metaclass = metaclass_name
Метакласс может быть специально использован в следующих ситуациях:
источник
Обратите внимание, что в Python 3.6 появился новый метод dunder,
__init_subclass__(cls, **kwargs)
который заменил множество распространенных вариантов использования метаклассов. Вызывается, когда создается подкласс определяющего класса. Смотрите документы по питону .источник
Метакласс - это своего рода класс, который определяет, как класс будет себя вести, или мы можем сказать, что класс сам является экземпляром метакласса.
источник