Метаклассы

Основные метаклассы

Когда 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 довольно «взломан», и концепция метакласса важна, если вы делаете продвинутые вещи, такие как метапрограммирование, или если вы хотите контролировать, как инициализируются ваши классы.