使用Boost.Python设置包装类的元类
我在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元类?.
1 个回答
0
如果 Boost 没有提供从 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
这段代码会自动将模块变量设置为在原生的 "_event" 模块中找到的任何名称,并且对于它遇到的每个类,创建一个新的类,改变元类,就像你在例子中所展示的那样。
这样做可能会导致元类冲突。如果发生这种情况,你可以让新创建的类成为原生类的代理,通过创建合适的 __getattribute__
和 __setattr__
方法来实现。如果你需要这样做,可以在评论中问我。