2014-10-26 6 views
0

Я написал следующий метакласс:Дополнительные аргументы в метаклассе

class FieldHandlerBase(type): 
    def __new__(cls, name, bases, dct, model): 
     ... 
     return super(FieldHandlerBase, cls).__new__(cls, name, bases, dct) 

Теперь я пытаюсь динамически создать класс, используя вышеупомянутый метакласс:

FieldHandlerBase(
    '%sFieldHandler' % name, 
    (FieldHandler,), 
    {rel_type: dct.setdefault(rel_type,()) for rel_type in REL_TYPES}, 
    model=name) 

Но он бросает мне эту ошибку:

>   model=name) 
E  TypeError: Error when calling the metaclass bases 
E   type.__init__() takes no keyword arguments 

Я не понимаю, почему, поскольку я называю базой метакласса (type здесь, с в FieldHandlerBase) с правильным количеством аргументов. Как я могу это исправить? Мне нужно передать дополнительный аргумент FieldHandlerBase, и я не хочу включать его в аргумент dct, так как он мне нужен только на уровне метакласса.

ответ

1

Вам необходимо написать метод __init__, а также метод __new__. В противном случае python вызовет type.__init__ для вашего нового класса, который не принимает никаких дополнительных аргументов.

например.

class FieldHandlerBase(type): 

    def __init__(cls, name, bases, attrs, model): 
     type.__init__(cls, name, bases, attrs) 
     cls.model = model 

    def __new__(metacls, name, bases, attrs, model): 
     ... 
     return type.__new__(metacls, name, bases, attrs) 

class ExampleFieldHandler(FieldHandler, metaclass=FieldHandlerBase, 
     model="Example"): 
    clsvar = "var" 

# or 
ExampleFieldHandler = FieldHandlerBase(
    "ExampleFieldHandler", 
    (FieldHandler,), 
    {"clsvar": "var"}, 
    model="Example" 
) 

assert ExampleFieldHandler.model == "Example" 
+0

О, я думал, что '__init __()' будет вызываться с теми же аргументами, что и '__new __()'. Спасибо! – linkyndy

+0

Это так. И в этом проблема. Поскольку вы не определили свой собственный '__init__', вызывается' __init__' на суперкласс (тип). Тип '__init__' type не принимает модель в качестве параметра, и поэтому вызов завершается с ошибкой. – Dunes

+0

Я имел в виду второй вызов '__new __()', тот, который я делаю для суперкласса ('type'), и где я точно не принимаю аргумент' model'. Но если я правильно понимаю, вызовы '__new __()' и '__init __()' отправляются из другого места, и оба они имеют одинаковые аргументы, независимо от того, что я делаю в этих двух методах. Теперь, из любопытства, кто точно отправляет вызовы на '__new __()' и '__init __()'? – linkyndy

Смежные вопросы