Python Language
Метаклассы
Поиск…
Вступление
Метаклассы позволяют вам глубоко модифицировать поведение классов Python (с точки зрения их определения, создания экземпляров, доступа и т. Д.) Путем замены метакласса type
который новые классы используют по умолчанию.
замечания
При проектировании вашей архитектуры учитывайте, что многие вещи, которые могут выполняться с помощью метаклассов, также могут быть выполнены с использованием более простой семантики:
- Традиционного наследования часто более чем достаточно.
- Декораторы классов могут сочетать функциональность с классами по специальному подходу.
- Python 3.6 представляет
__init_subclass__()
который позволяет классу участвовать в создании своего подкласса.
Основные метаклассы
Когда type
вызывается с тремя аргументами, он ведет себя как класс (meta) и создает новый экземпляр, т. Е. он создает новый класс / тип.
Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__ # <type 'type'>
Dummy().__class__.__class__ # <type 'type'>
type
подкласса можно создать для пользовательского метакласса.
class mytype(type):
def __init__(cls, name, bases, dict):
# call the base initializer
type.__init__(cls, name, bases, dict)
# perform custom initialization...
cls.__custom_attribute__ = 2
Теперь у нас есть новый mytype
который можно использовать для создания классов таким же образом, как и type
.
MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__ # <class '__main__.mytype'>
MyDummy().__class__.__class__ # <class '__main__.mytype'>
MyDummy.__custom_attribute__ # 2
Когда мы создаем новый класс с использованием ключевого слова class
метаклас по умолчанию выбирается на основе базовых классов.
>>> class Foo(object):
... pass
>>> type(Foo)
type
В приведенном выше примере единственным базовым классом является object
поэтому наш метакласс будет типом object
, который является type
. Можно переопределить значение по умолчанию, однако это зависит от того, используем ли мы Python 2 или Python 3:
Для определения метакласса можно использовать специальный атрибут __metaclass__
.
class MyDummy(object):
__metaclass__ = mytype
type(MyDummy) # <class '__main__.mytype'>
Специальный metaclass
аргумент ключевого слова определяет метакласс.
class MyDummy(metaclass=mytype):
pass
type(MyDummy) # <class '__main__.mytype'>
Любые аргументы ключевых слов (кроме metaclass
) в объявлении класса будут переданы в метакласс. Таким образом, class MyDummy(metaclass=mytype, x=2)
передаст x=2
в качестве аргумента ключевого слова в конструктор mytype
.
Прочтите это подробное описание метаклассов python для более подробной информации.
Синглтоны, использующие метаклассы
Синглтон - это шаблон, который ограничивает экземпляр класса одним экземпляром / объектом. Для получения дополнительной информации о шаблонах проектирования синглтона python см. Здесь .
class SingletonType(type):
def __call__(cls, *args, **kwargs):
try:
return cls.__instance
except AttributeError:
cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls.__instance
class MySingleton(object):
__metaclass__ = SingletonType
class MySingleton(metaclass=SingletonType):
pass
MySingleton() is MySingleton() # True, only one instantiation occurs
Использование метакласса
Синтаксис метакласса
class MyClass(object):
__metaclass__ = SomeMetaclass
class MyClass(metaclass=SomeMetaclass):
pass
Совместимость с Python 2 и 3 с six
import six
class MyClass(six.with_metaclass(SomeMetaclass)):
pass
Пользовательские функции с метаклассами
Функциональность в метаклассах может быть изменена так, что всякий раз, когда создается класс, строка выводится на стандартный вывод или генерируется исключение. Этот метакласс отобразит имя создаваемого класса.
class VerboseMetaclass(type):
def __new__(cls, class_name, class_parents, class_dict):
print("Creating class ", class_name)
new_class = super().__new__(cls, class_name, class_parents, class_dict)
return new_class
Вы можете использовать метакласс следующим образом:
class Spam(metaclass=VerboseMetaclass):
def eggs(self):
print("[insert example string here]")
s = Spam()
s.eggs()
Стандартный выход будет:
Creating class Spam
[insert example string here]
Введение в метаклассы
Что такое метакласс?
В Python все является объектом: целые числа, строки, списки, даже функции и классы сами по себе являются объектами. И каждый объект является экземпляром класса.
Чтобы проверить класс объекта x, можно вызвать type(x)
, поэтому:
>>> type(5)
<type 'int'>
>>> type(str)
<type 'type'>
>>> type([1, 2, 3])
<type 'list'>
>>> class C(object):
... pass
...
>>> type(C)
<type 'type'>
Большинство классов в python являются экземплярами type
. сам type
также является классом. Такие классы, экземпляры которых также являются классами, называются метаклассами.
Самый простой метакласс
ОК, так что уже один метаклассом в Python: type
. Можем ли мы создать еще один?
class SimplestMetaclass(type):
pass
class MyClass(object):
__metaclass__ = SimplestMetaclass
Это не добавляет каких-либо функциональных возможностей, но это новый метакласс, см., Что MyClass теперь является экземпляром SimplestMetaclass:
>>> type(MyClass)
<class '__main__.SimplestMetaclass'>
Метакласс, который делает что-то
Метакласс, который делает что-то обычно, переопределяет type
__new__
, чтобы изменить некоторые свойства создаваемого класса, прежде чем вызывать исходный __new__
который создает класс:
class AnotherMetaclass(type):
def __new__(cls, name, parents, dct):
# cls is this class
# name is the name of the class to be created
# parents is the list of the class's parent classes
# dct is the list of class's attributes (methods, static variables)
# here all of the attributes can be modified before creating the class, e.g.
dct['x'] = 8 # now the class will have a static variable x = 8
# return value is the new class. super will take care of that
return super(AnotherMetaclass, cls).__new__(cls, name, parents, dct)
Метакласс по умолчанию
Возможно, вы слышали, что все в Python является объектом. Это правда, и все объекты имеют класс:
>>> type(1)
int
Литерал 1 является экземпляром int
. Давайте объявим класс:
>>> class Foo(object):
... pass
...
Теперь давайте создадим экземпляр:
>>> bar = Foo()
Что такое класс bar
?
>>> type(bar)
Foo
Ницца, bar
- это пример Foo
. Но каков класс самого Foo
?
>>> type(Foo)
type
Хорошо, сам Foo
является экземпляром type
. Как насчет type
?
>>> type(type)
type
Итак, что такое метакласс? Пока давайте притвориться, что это просто причудливое имя для класса класса. Takeaways:
- Все это объект в Python, поэтому все имеет класс
- Класс класса называется метаклассом
- Метакласс по умолчанию - это
type
, и на сегодняшний день он является наиболее распространенным метаклассом
Но почему вы должны знать о метаклассах? Ну, сам Python довольно «взломан», и концепция метакласса важна, если вы занимаетесь продвинутыми вещами, такими как мета-программирование, или если вы хотите контролировать, как инициализируются ваши классы.