使用 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:元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类