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

Posted

技术标签:

【中文标题】使用 Boost.Python 设置包装类的元类【英文标题】:Setting metaclass of wrapped class with Boost.Python 【发布时间】:2012-02-20 16:40:20 【问题描述】:

我有一个用 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 中,the safe way 更改元类就是这样做:

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 定义元类的方法,这就是我打开 How to define a Python metaclass with Boost.Python? 的原因。

【问题讨论】:

可能是class EventWithMeta(Event, metaclass=EventMeta):pass,然后是class KeyboardEvent(EventWithMeta); class AnotherEvent(EventWithMeta) @reclosedev 不。问题不在于我输入“元类”这个词。元类的需求是一个实现细节,不应该泄漏到暴露给脚本的接口。 也许我遗漏了一些东西,但在这种情况下,Event 可以重命名为 _Event 或类似的东西,EventWithMeta 可以重命名为 Event @reclosedev 这是一个显而易见的解决方案,但在我的情况下它有很多缺点。 更改类的元类与更改实例的类一样有意义,即您可以这样做,但很少会产生任何可用的东西。按照 reclosedev 建议的方式进行操作有哪些缺点? 【参考方案1】:

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

它可以或多或少地通过一点点内省自动完成。假设你的 boost 模块被命名为“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__ 方法使新创建的类成为本地类的代理。只需在评论中询问您是否需要这样做。

【讨论】:

很遗憾,我无法在 Python 中定义元类。它需要做的初始化是使自定义 RTTI 系统与 C++ 事件以及 Python 事件一起工作。我可以向 Python 公开足够多的 C++ 实现细节,因此脚本可以进行所需的初始化,但这不是一个好的解决方案。

以上是关于使用 Boost.Python 设置包装类的元类的主要内容,如果未能解决你的问题,请参考以下文章

子类避免父类的元类

TypeError:元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类

如何使用 Boost.Python 定义 Python 元类?

在 Groovy 中,实例的元类与其类的元类有啥区别

python中的元类作用?

TypeError:元类冲突:派生类的元类