[Python, Программирование] Метаклассы в Python (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Перевод статьи подготовлен в преддверии старта курса "Python Developer. Basic".
Метаклассы – это такие классы, экземпляры которых сами являются классами. Подобно тому, как «обычный» класс определяет поведение экземпляров класса, метакласс определяет и поведение классов, и поведение их экземпляров.Метаклассы поддерживаются не всеми объектно-ориентированными языками программирования. Те языки программирования, которые их поддерживают, значительно отличаются по способу их реализации. Но в Python метаклассы есть.Некоторые программисты рассматривают метаклассы в Python как «решения, которые ждут или ищут задачу».У метаклассов множество применений. Выделим несколько из них:
- Логирование и профилирование;
- Тестирование интерфейса;
- Регистрация классов во время создания;
- Автоматическое создание свойств;
- Прокси;
- Автоматическая блокировка/синхронизация ресурсов.
Определение метаклассовВ целом, метаклассы определяются также, как и любые другие классы в Python, но это классы, которые наследуются от «типа». Еще одно отличие в том, что метакласс вызывается автоматически, когда оператор класса, использующий метакласс, заканчивается. Другими словами, если ключевое слово metaclass не передается после базовых классов заголовка класса (однако базовых классов может и не быть), то будет вызван type() (т.е. _call_ типа). С другой стороны, если ключевое слово metaclass используется, то назначенный ему класс будет вызываться вместо type. Давайте создадим совсем простой метакласс. Он ничего не умеет, кроме вывода содержимого своих аргументов в методе_new_ и возврата результата вызова type._new_:
class LittleMeta(type):
def __new__(cls, clsname, superclasses, attributedict):
print("clsname: ", clsname)
print("superclasses: ", superclasses)
print("attributedict: ", attributedict)
return type.__new__(cls, clsname, superclasses, attributedict)
А теперь используем метакласс LittleMeta в следующем примере:
class S:
pass
class A(S, metaclass=LittleMeta):
pass
a = A()
clsname: A
superclasses: (<class '__main__.S'>,)
attributedict: {'__module__': '__main__', '__qualname__': 'A'}
Мы видим, что был вызван LittleMeta._new_, а не type._new_. Давайте определим метакласс EssentialAnswers, который может автоматически включать наш метод augmen_tanswer:
x = input("Do you need the answer? (y/n): ")
if x.lower() == "y":
required = True
else:
required = False
def the_answer(self, *args):
return 42
class EssentialAnswers(type):
def __init__(cls, clsname, superclasses, attributedict):
if required:
cls.the_answer = the_answer
class Philosopher1(metaclass=EssentialAnswers):
pass
class Philosopher2(metaclass=EssentialAnswers):
pass
class Philosopher3(metaclass=EssentialAnswers):
pass
plato = Philosopher1()
print(plato.the_answer())
kant = Philosopher2()
# let's see what Kant has to say :-)
print(kant.the_answer())
Do you need the answer? (y/n): y
42
42
В главе «Type and Class Relationship» мы выяснили, что после обработки определения класса Python вызывает:
type(classname, superclasses, attributes_dict)
Но не в том случае, когда метакласс был объявлен в заголовке. Именно так мы и сделали в нашем прошлом примере. Наши классы Philosopher1, Philosopher2 и Philosopher3 были «прицеплены» к метаклассу EssentialAnswers. И вот почему EssentialAnswers будет вызван вместо type:
EssentialAnswer(classname, superclasses, attributes_dict)
Если быть точным, то аргументам вызовов будет даны следующие значения:
EssentialAnswer('Philopsopher1',
(),
{'__module__': '__main__', '__qualname__': 'Philosopher1'})
Другие классы Philosopher будут вести себя аналогично.Создаем синглтоны с помощью метаклассов Синглтон - это шаблон проектирования, который позволяет создать всего один экземпляр класса. Он используется в тех случаях, когда нужен ровно один объект. Понятие может быть обобщено, то есть мы можем ограничить создание экземпляров класса определенным или фиксированным количеством. Сам термин пришел к нам из математики, где синглтон, также называемый единичным множеством, используется для обозначения множества с всего одним элементом.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=Singleton):
pass
class RegularClass():
pass
x = SingletonClass()
y = SingletonClass()
print(x == y)
x = RegularClass()
y = RegularClass()
print(x == y)
True
False
Также мы можем создавать Singleton-классы, наследуясь от Singleton, который можно определить следующим образом:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
class SingletonClass(Singleton):
pass
class RegularClass():
pass
x = SingletonClass()
y = SingletonClass()
print(x == y)
x = RegularClass()
y = RegularClass()
print(x == y)
True
False
Узнать подробнее о курсе.Читать ещё:
- Почему стоит начать использовать FastAPI прямо сейчас
- В каких случаях не нужно использовать списки в Python
- Введение в асинхронное программирование на Python
===========
Источник:
habr.com
===========
===========
Автор оригинала: Bernd Klein, Bodenseo; Design by Denise Mitchinson adapted for python-course.eu by Bernd Klein
===========Похожие новости:
- [PHP, Программирование, Laravel] Печатные формы документов для Eloquent в 0 строчек кода
- [JavaScript, Программирование, Я пиарюсь, Lisp] Как я устал от JavaScript и создал свой собственный язык программирования
- [Программирование, Data Mining, ООП, R, Data Engineering] ООП в языке R (часть 2): R6 классы
- [Разработка веб-сайтов, JavaScript, Программирование] Пример практического использования модулей
- [Python, Разработка под Android, Разработка под MacOS, Разработка под Linux, Разработка под Windows] Дополнительные компоненты для кроссплатформеннной библиотеки материального дизайна KivyMD
- [Профессиональная литература] Издательство Питер. Колонка редактора
- [Промышленное программирование, Разработка робототехники, Программирование микроконтроллеров, Производство и разработка электроники] ModBus Slave RTU/ASCII без смс и регистрации. Версия 3
- [Python, Программирование] Напишем и поймем Decision Tree на Python с нуля! Часть 5. Информационная энтропия (перевод)
- [Мессенджеры, JavaScript, Программирование, VueJS] Как создать приложение-чат за двадцать минут (перевод)
- [Разработка веб-сайтов, JavaScript, Программирование] Как анимировать элемент «details» с помощью WAAPI (перевод)
Теги для поиска: #_python, #_programmirovanie (Программирование), #_python, #_metaclasses, #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_python, #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:21
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Перевод статьи подготовлен в преддверии старта курса "Python Developer. Basic".
class LittleMeta(type):
def __new__(cls, clsname, superclasses, attributedict): print("clsname: ", clsname) print("superclasses: ", superclasses) print("attributedict: ", attributedict) return type.__new__(cls, clsname, superclasses, attributedict) class S:
pass class A(S, metaclass=LittleMeta): pass a = A() clsname: A
superclasses: (<class '__main__.S'>,) attributedict: {'__module__': '__main__', '__qualname__': 'A'} x = input("Do you need the answer? (y/n): ")
if x.lower() == "y": required = True else: required = False def the_answer(self, *args): return 42 class EssentialAnswers(type): def __init__(cls, clsname, superclasses, attributedict): if required: cls.the_answer = the_answer class Philosopher1(metaclass=EssentialAnswers): pass class Philosopher2(metaclass=EssentialAnswers): pass class Philosopher3(metaclass=EssentialAnswers): pass plato = Philosopher1() print(plato.the_answer()) kant = Philosopher2() # let's see what Kant has to say :-) print(kant.the_answer()) Do you need the answer? (y/n): y
42 42 type(classname, superclasses, attributes_dict)
EssentialAnswer(classname, superclasses, attributes_dict)
EssentialAnswer('Philopsopher1',
(), {'__module__': '__main__', '__qualname__': 'Philosopher1'}) class Singleton(type):
_instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class SingletonClass(metaclass=Singleton): pass class RegularClass(): pass x = SingletonClass() y = SingletonClass() print(x == y) x = RegularClass() y = RegularClass() print(x == y) True
False class Singleton(object):
_instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = object.__new__(cls, *args, **kwargs) return cls._instance class SingletonClass(Singleton): pass class RegularClass(): pass x = SingletonClass() y = SingletonClass() print(x == y) x = RegularClass() y = RegularClass() print(x == y) True
False
=========== Источник: habr.com =========== =========== Автор оригинала: Bernd Klein, Bodenseo; Design by Denise Mitchinson adapted for python-course.eu by Bernd Klein ===========Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_python, #_programmirovanie ( Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:21
Часовой пояс: UTC + 5