Для чего нужны метаклассы Python?
Что можно сделать с помощью метаклассов, которые не могут быть другими?
Алекс Мартелли сказал, что есть задачи, которые не могут быть достигнуты без метаклассов здесь Python metaclasses vs class decorators
Я хотел бы узнать, какие?
Ответы
Ответ 1
Метаклассы незаменимы, если вы хотите иметь объекты класса (в отличие от экземпляров объектов класса), оснащенных "специальным настраиваемым поведением", поскольку поведение объекта зависит от специальных методов на тип объекта, а тип объекта класса является, в точности, синонимом метакласса.
Например, если вы хотите, чтобы объект класса X, из которого исходит "print X", "Time is now 8:46 am" (в 8:46 или, в более общем случае, текущее время), это должно означать, что type(x)
(Метакласс AKA X) имеет специальный настраиваемый метод __str__
- и аналогичным образом (с различными применимыми специальными методами), если вы хотите придать смысл выражениям, таким как X + Y
, где X и Y являются объектами класса, или X[23]
(где X, опять же, является объектом класса) и т.д.
Теперь большинство других задач настройки (в Python 2.6 или лучше) проще реализовать с помощью декоратора класса, который может изменить объект класса сразу после окончания инструкции class
. Есть еще несколько случаев, когда это невозможно, потому что изменения должны быть сделаны очень рано, если они должны иметь какой-либо эффект (например, установка или изменение __slots__
).
В Python 3 метаклассы получают один дополнительный бит полезности: метакласс теперь может дополнительно указать объект сопоставления, который будет заполняться во время выполнения тела оператора class
(по умолчанию это обычный dict
). Это позволяет сохранить и использовать порядок привязок имен в кубе класса (в то время как нормальный dict
теряет порядок), что иногда приятно, когда класс должен иметь "поля" в определенном конкретном порядке (например, для сопоставления 1:1 на C struct
, строку в файле CSV или таблице БД и т.п.) - в Python 2. * это должно было быть избыточно указано (обычно с дополнительным атрибутом класса, который имеет последовательность и, следовательно, сохраняет порядок), и эта функция метаданных Python 3 позволяет удалить избыточность.
Ответ 2
Добавьте дополнительную гибкость в программирование:
Но в соответствии с этим Программирование метакласса в Python вам могут не понадобиться (пока)
Метаклассы более глубокие, чем 99% пользователей должны когда-либо беспокоиться. Если вы задаетесь вопросом, нужны ли вам они, вы не делаете (люди, которые действительно нуждаются в них, знают с уверенностью, что они в них нуждаются, и не нуждаются в объяснении о том, почему).
- Python Guru Тим Петерс
Ответ 3
Я использую метаклассы с некоторой частотой, и они являются чрезвычайно мощным инструментом для инструментария. Иногда ваше решение проблемы может быть более элегантным, меньше кода, чем с ним.
То, что я чаще всего использую метаклассы, - это пост-обработку атрибутов класса при создании класса. Например, устанавливая атрибут name
для объектов, где это необходимо (например, как может работать ORM Django):
class AutonamingType(type):
def __init__(cls, name, bases, attrs):
for k,v in attrs.iteritems():
if getattr(v, '__autoname__', False):
v.name = k
class Autonamer(object):
__metaclass__ = AutonamingType
Если у вас есть это как инструмент, и вы используете класс, который должен знать его name
, прежде чем он сможет do_something()
:
class Foo(object):
__autoname__ = True
def __init__(self, name=None):
self.name = name
def do_something(self):
if self.name is None:
raise ValueError('name is None')
# now, do something
Это может сделать разницу между остальной частью вашего кода:
class Bar(object):
myfoo1 = Foo('myfoo1')
myfoo2 = Foo('myfoo2')
myfoo3 = Foo('myfoo3')
и это:
class Baaz(Autonamer):
myfoo1 = Foo()
myfoo2 = Foo()
myfoo3 = Foo()
Таким образом, сокращение дублирования (и вероятность того, что имя переменной и назначенное имя могут выйти из синхронизации).
Ответ 4
Если вы ищете примеры использования механизма метакласса, вы можете прочитать исходный код django.forms.
Декларативный стиль определения формы реализуется через метакласс.
Ответ 5
Они редко нужны, но полезны в тех местах, где вы хотите добавить поведение к основному поведению объекта - сравните Aspect Oriented Programming или инструментарий, выполненный в таких системах, как Hibernate.
Например, вам может понадобиться класс, который сохраняется или регистрирует каждый новый объект.
Ответ 6
Наверное, нет ничего, что можно было бы сделать исключительно с метаклассами, но для некоторых людей (включая мои) это интересный инструмент, который вы можете использовать. Просто будьте осторожны, чтобы не злоупотреблять, поскольку это может быть сложно.
Например, я использовал метапрограммирование в недавнем проекте. Это был лист OpenOffice calc, который, используя некоторые макросы pyUNO, генерирует некоторые файлы с информацией. Был один лист, который представляет пользователю информацию для заполнения, а остальные могут использоваться для описания типов элементов и их свойств. Затем пользователь может выбрать количество элементов и тип каждого и сгенерировать файлы.
Макрос создаст класс с помощью метапрограммирования, следующего за конфигурацией на каждом листе. Затем пользователь может инициализировать каждый класс и генерировать объекты.
Это можно сделать без метапрограммирования, но мне показалось естественным использовать возможности метапрограммирования для этого.
Ответ 7
Взгляните на источники Django - например, для генерации моделей используются метаклассы.
http://code.djangoproject.com/wiki/DynamicModels
Внутренне Django использует метаклассы для создавать модели, основанные на классе, который вы укажите в своем исходном коде. Без слишком много деталей, означает, что вместо ваших классов являясь фактическими моделями, Django получает описание вашего класса, который он использует для создания модели в своем место.
Ответ 8
Первый комментатор заявляет, что использование метаклассов здесь было "драгоценным камнем", которое помогло ему отследить неожиданные ошибки, которые происходили ( много дней'.