Вот моя проблема. Я хочу, чтобы следующий класс имел набор атрибутов свойства. Я мог или записать им всем как foo
и bar
, или на основе некоторых других примеров я видел, похоже, что я мог использовать декоратора класса, метакласс, или переопределить __new__
метод для установки свойств автоволшебно. Я просто не уверен, какой "правильный" способ сделать это был бы.
class Test(object):
def calculate_attr(self, attr):
# do calculaty stuff
return attr
@property
def foo(self):
return self.calculate_attr('foo')
@property
def bar(self):
return self.calculate_attr('bar')
Магия - это плохо. Это затрудняет понимание и поддержку вашего кода. Вам практически никогда не понадобятся метаклассы или __ new __
.
Похоже, ваш вариант использования можно реализовать с помощью довольно простого кода (с небольшим намеком на волшебство):
class Test(object):
def calculate_attr(self, attr):
return something
def __getattr__(self, name):
return self.calculate_attr(name)
Метакласс используется, когда создается новый класс, а не экземпляр. Таким образом вы можете, например, регистрировать классы (django делает это и использует, например, для создания таблиц в базе данных). Поскольку class
- это инструкция, которую вы можете рассматривать как декоратор для класса.
Метакласс __ new __
не становится __ new __
для создаваемого вами класса - он используется для создания самого класса. Фактический объект класса возвращается метаклассом. Новый экземпляр класса возвращается __ new __
.
Рассмотрим следующий (безумный) код:
def MyMetaClass(name, bases, dict):
print "name", name
print "bases", bases
print "dict", dict
return 7
class C('hello', 'world'):
__metaclass__ = MyMetaClass
foo = "bar"
def baz(self, qux):
pass
print "C", C
(Я использовал функцию вместо класса в качестве метакласса. Любой вызываемый объект может использоваться как метакласс, но многие люди предпочитают править свои как классы, наследуемые от type
с переопределением new. Различия между этой функцией незначительны.)
Она выводит
name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7
Помогает ли это вам лучше понять, что такое метаклассы ?
Вы очень редко потребуется определять собственный метакласс.