Основные метаклассы
Когда type
вызывается с тремя аргументами он ведет себя как (мета) класс она есть, и создает новый экземпляр, то есть. это производит новый класс / тип.
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
ключевого слово метакласса по умолчанию выбирается на основе на BASECLASSES.
>>> class Foo(object):
... pass
>>> type(Foo)
type
В приведенном выше примере только BaseClass является 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
конструктора.
Прочтите это описание в углубленную питона мета-классов для более подробной информации.
Синглтоны с использованием метаклассов
Синглтон - это шаблон, который ограничивает создание экземпляра класса одним экземпляром / объектом. Для получения дополнительной информации о питоных одноэлементных шаблонах проектирования, см здесь .
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
Класс MySingleton (объект): __metaclass__ = SingletonType класс MySingleton (metaclass = SingletonType): проход
MySingleton() is MySingleton() # True, only one instantiation occurs
Использование метакласса
Синтаксис метакласса
класс MyClass (объект): __metaclass__ = SomeMetaclass класс MyClass (metaclass = SomeMetaclass): проход
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 все является объектом: целые числа, строки, списки, даже функции и сами классы являются объектами. И каждый объект является экземпляром класса.
Для того, чтобы проверить класс объекта х, можно назвать 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
«S __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 довольно «взломан», и концепция метакласса важна, если вы делаете продвинутые вещи, такие как метапрограммирование, или если вы хотите контролировать, как инициализируются ваши классы.