Metaclass в Python: что такое метаклассы?
В этом уроке вы узнаете, что такое метаклассы в Python и поймете, как использовать metaclass для создания других классов.
- Что такое метакласс в Python?
- Пример метакласса Python
- Параметры метакласса
- Когда используются метаклассы в Python?
Что такое метакласс в Python?
Метакласс — это класс, который создает другие классы. По умолчанию Python использует метакласс type для создания других классов.
Например, следующий код определяет класс Person:
class Person: def __init__(self, name, age): self.name = name self.age = age
Когда Python выполняет код, он использует метакласс type для создания класса Person. Причина в том, что класс Person по умолчанию использует метакласс type.
Явное определение класса Person выглядит следующим образом:
class Person(object, metaclass=type): def __init__(self, name, age): self.name = name self.age = age
Аргумент метакласса позволяет указать, какой класс метакласса использовать для определения класса. Таким образом, вы можете создать собственный метакласс со своей собственной логикой для создания других классов. Используя собственный метакласс, вы можете добавить функциональность в процесс создания класса.
Пример метакласса Python
- Сначала определите собственный метакласс под названием Human, у которого атрибут freedom по умолчанию установлен в значение True:
class Human(type): def __new__(mcs, name, bases, class_dict): class_ = super().__new__(mcs, name, bases, class_dict) class_.freedom = True return class_
Обратите внимание, что метод __new__ возвращает новый класс или объект класса.
- Во-вторых, определите класс Person, который использует метакласс Human:
class Person(object, metaclass=Human): def __init__(self, name, age): self.name = name self.age = age
Класс Person будет иметь атрибут freedom, как показано в переменных класса:
pprint(Person.__dict__)
Выход:
mappingproxy({'__dict__': <attribute '__dict__' of 'Person' objects>, '__doc__': None, '__init__': <function Person.__init__ at 0x000001E716C71670>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Person' objects>, 'freedom': True})
Полный код:
from pprint import pprint class Human(type): def __new__(mcs, name, bases, class_dict): class_ = super().__new__(mcs, name, bases, class_dict) class_.freedom = True return class_ class Person(object, metaclass=Human): def __init__(self, name, age): self.name = name self.age = age pprint(Person.__dict__)
Параметры метакласса
Чтобы передать параметры в метакласс, вы используете аргументы ключевого слова. Например, следующий пример переопределяет метакласс Human, который принимает аргументы ключевого слова, где каждый аргумент становится переменной класса:
class Human(type): def __new__(mcs, name, bases, class_dict, **kwargs): class_ = super().__new__(mcs, name, bases, class_dict) if kwargs: for name, value in kwargs.items(): setattr(class_, name, value) return class_
В следующем примере метакласс Human используется для создания класса Person с переменными класса country и freedom, со значениями USA и True соответственно:
class Person(object, metaclass=Human, country='USA', freedom=True): def __init__(self, name, age): self.name = name self.age = age
Вот переменные класса Person:
pprint(Person.__dict__)
Выход:
mappingproxy({'__dict__': <attribute '__dict__' of 'Person' objects>, '__doc__': None, '__init__': <function Person.__init__ at 0x0000018A334235E0>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Person' objects>, 'country': 'USA', 'freedom': True})
Полный код:
from pprint import pprint class Human(type): def __new__(mcs, name, bases, class_dict, **kwargs): class_ = super().__new__(mcs, name, bases, class_dict) if kwargs: for name, value in kwargs.items(): setattr(class_, name, value) return class_ class Person(object, metaclass=Human, freedom=True, country='USA'): def __init__(self, name, age): self.name = name self.age = age pprint(Person.__dict__)
Когда используются метаклассы в Python?
Вот цитата Тима Питерса, написавшего «Дзен Python»:
Метаклассы — глубже, чем магия, о которой 99% пользователей никогда не стоит задумываться. Если вы задаетесь вопросом, нужны ли они вам, то нет (люди, которым они действительно нужны, точно это знают, и им не нужны объяснения, почему).
Тим Питерс
На практике обычно вам не нужно использовать метаклассы, если вы не поддерживаете или не разрабатываете ядро больших фреймворков, таких как Django.