Установка метакласса обернутого класса с Boost.Python - PullRequest
5 голосов
/ 27 января 2012

У меня есть класс Event, определенный в C ++, который я открываю для Python, используя Boost.Ожидается, что мои сценарии будут производными от этого класса, и я хотел бы выполнить некоторую инициализацию при каждом определении нового дочернего класса.

Как я могу установить метакласс открытого класса Event таким образом, чтобы всякий раз, когдаСценарий Python является производным от этого класса, метакласс может выполнить необходимую инициализацию?

Я хотел бы избежать необходимости явно использовать метакласс в сценариях ...

class KeyboardEvent(Event):  # This is what I want
    pass

class KeyboardEvent(Event, metaclass=EventMeta): # This is not a good solution
    pass

Редактировать: Часть решения

Кажется, нет способа установить метакласс с помощью Boost.Python.Следующая лучшая вещь - импровизировать и изменять метакласс после определения класса.В нативном Python безопасный способ изменить метакласс заключается в следующем:

B = MetaClass(B.__name__, B.__bases__, B.__dict__)

В Boost это будет выглядеть примерно так:

BOOST_PYTHON_MODULE(event)
{
    using namespace boost::python;
    using boost::python::objects::add_to_namespace;

    class_<EventMetaClass> eventmeta("__EventMetaClass")
        ...;

    class_<Event> event("Event")
        ...;

    add_to_namespace(scope(), "Event",
        eventmeta(event["__name__"], event["__bases__"], event["__dict__"]));
}

Проблема в том, что я не могу найти способ определить метакласс с Boost.Python, поэтому я открыл Как определить метакласс Python с Boost.Python? .

1 Ответ

0 голосов
/ 31 января 2012

Если boost не предлагает способа сделать это с помощью cn ++ и, похоже, этого не происходит, можно пойти путем создания классов-оболочек, реализующих метакласс -

Это можно сделатьболее или менее автоматически назначает немного инстроспекции.Давайте предположим, что ваш модуль наддува называется «event» - вы должны либо назвать файл как _event, либо поместить его в свой модуль, и написать файл python с именем «event.py» (или файл __init__.py в вашем модуле, который бывыполните более или менее это:

import _event

class eventmeta(type):
    ...

event_dict = globals()
for key, value in _event.__dict__.items():
    if isinstance(value, type):
        event_dict[key] = eventmeta(key, (value,),{})
    else:
        #set other module members as members of this module
        event_dict[key] = value

del key, value, event_dict

Thos cpde автоматически установит переменные модуля, равные любым именам, найденным в собственном модуле "_event" - и для каждого класса, с которым он столкнется, создайте новый класс, изменяющий метакласс,как в вашем примере.

Может случиться так, что вы получите конфликт метаклассов, выполнив это. Если это так, то способ сделать вновь созданные классы прокси по отношению к собственным классам, создав надлежащие __getattribute__и __setattr__ методов. Просто спросите в комментарии, нужно ли вам это делать.

...