使用 Boost.Python 设置包装类的元类

发布于 2024-12-29 04:09:56 字数 1193 浏览 4 评论 0原文

我有一个用 C++ 定义的 Event 类,我使用 Boost 将其公开给 Python。我的脚本应该从此类派生,并且每当定义新的子类时我都想进行一些初始化。

如何设置公开的 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 定义元类的方法,这就是我打开 如何使用 Boost.Python 定义 Python 元类?

I have an Event class defined in C++ that I expose to Python using Boost. My scripts are expected to derive from this class, and I'd like to do some initialization whenever a new child class is defined.

How can I set the metaclass of the exposed Event class such that whenever a Python script derives from this class, the metaclass could do the required initialization?

I would like to avoid having to explicitly use a metaclass in the scripts...

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

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

Edit: Part of the solution

It seems there's no way to set the metaclass with Boost.Python. The next best thing is to improvise and change the metaclass after the class was defined. In native Python, the safe way to change a metaclass is to do this:

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

In Boost, it'd look something like this:

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__"]));
}

The problem is that I can't seem to find a way to define a metaclass with Boost.Python, which is why I've opened How to define a Python metaclass with Boost.Python?.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜`诱少女 2025-01-05 04:09:56

如果 boost 没有提供从 c++ 中做到这一点的方法,而且看起来也没有,那么可行的方法是创建实现元类的包装类 -

它可以或多或少地自动完成,使用一点点内省。假设您的 boost 模块名为“event” - 您应该将该文件命名为 _event 或将其放入模块中,并编写一个名为“event.py”的 python 文件(或 __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__ 来使新创建的类成为本机类的代理。 > 方法,只需在评论中询问您是否需要这样做。

If boost does not offer a way to do it from withn c++, and it looks like it don't, the way to go is to create wrapper classes that implement the metaclass -

It can be done more or less automatically usign a ittle bit of instrospection. Let's suppose your boost module is named "event" - you should either name the file as _event or place it inside you module, and write an python file - named "event.py" (or an __init__.py file on your module that would do more or less this:

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 will automatically set module variables equal to any names found in the native"_event" module - and for each class it encounters, create a new class changing the metaclass, as in your example.

It may be that you get a metaclass conflict by doing this. If so, the way is to make the newly created classes to be proxies to the native classes, by creating proper __getattribute__ and __setattr__ methods. Just ask in a comment if you will need to do that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文