cppyy
概述#
cppyy 是一个自动的、运行时的 Python-C++绑定生成器,用于从Python调用C++以及从C++调用Python。运行时生成能够实现更详细的特化以获得更高的性能,延迟加载以减少大规模项目中的内存使用,Python端的交叉继承和回调以便与C++框架一起工作,运行时模板实例化,自动对象向下转换,异常映射,以及C++库的交互式探索。cppyy在不需要任何语言扩展、中间语言或手写样板代码的情况下提供了这些功能。
cppyy
基于 Cling,这是 C++ 解释器,用于匹配 Python 的动态性、交互性和运行时行为。
import cppyy
cppyy.cppdef("""
class MyClass {
public:
MyClass(int i) : m_data(i) {}
virtual ~MyClass() {}
virtual int add_int(int i) { return m_data + i; }
int m_data;
};""")
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 1
----> 1 import cppyy
3 cppyy.cppdef("""
4 class MyClass {
5 public:
(...)
9 int m_data;
10 };""")
ModuleNotFoundError: No module named 'cppyy'
from cppyy.gbl import MyClass
m = MyClass(42)
cppyy.cppdef("""
void say_hello(MyClass* m) {
std::cout << "Hello, the number is: " << m->m_data << std::endl;
}""")
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[2], line 1
----> 1 from cppyy.gbl import MyClass
2 m = MyClass(42)
3 cppyy.cppdef("""
4 void say_hello(MyClass* m) {
5 std::cout << "Hello, the number is: " << m->m_data << std::endl;
6 }""")
ModuleNotFoundError: No module named 'cppyy'
MyClass.say_hello = cppyy.gbl.say_hello
m.say_hello()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[3], line 1
----> 1 MyClass.say_hello = cppyy.gbl.say_hello
2 m.say_hello()
NameError: name 'cppyy' is not defined
m.m_data = 13
m.say_hello()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 1
----> 1 m.m_data = 13
2 m.say_hello()
NameError: name 'm' is not defined
class PyMyClass(MyClass):
def add_int(self, i): # python side override (CPython only)
return self.m_data + 2*i
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 1
----> 1 class PyMyClass(MyClass):
2 def add_int(self, i): # python side override (CPython only)
3 return self.m_data + 2*i
NameError: name 'MyClass' is not defined
cppyy.cppdef("int callback(MyClass* m, int i) { return m->add_int(i); }")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[6], line 1
----> 1 cppyy.cppdef("int callback(MyClass* m, int i) { return m->add_int(i); }")
NameError: name 'cppyy' is not defined
cppyy.gbl.callback(m, 2) # calls C++ add_int
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[7], line 1
----> 1 cppyy.gbl.callback(m, 2) # calls C++ add_int
NameError: name 'cppyy' is not defined
cppyy.gbl.callback(PyMyClass(1), 2) # calls Python-side override
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[8], line 1
----> 1 cppyy.gbl.callback(PyMyClass(1), 2) # calls Python-side override
NameError: name 'cppyy' is not defined
凭借现代的 C++ 编译器作为后盾,cppyy 是未来证明的。请看下面这个使用 boost::any
的会话,这是在 C++ 中允许异质容器的封装类型。Boost 库以其对现代 C++ 的大胆使用和大量模板使用而闻名:
import cppyy
cppyy.include('boost/any.hpp') # assumes you have boost installed
from cppyy.gbl import std, boost
val = boost.any() # the capsule
>>> val.__assign__(std.vector[int]()) # assign it a std::vector<int>
<cppyy.gbl.boost.any object at 0xf6a8a0>
>>> val.type() == cppyy.typeid(std.vector[int]) # verify type
True
>>> extract = boost.any_cast[int](std.move(val)) # wrong cast
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cppyy.gbl.boost.bad_any_cast: Could not instantiate any_cast<int>:
int boost::any_cast(boost::any&& operand) =>
wrapexcept<boost::bad_any_cast>: boost::bad_any_cast: failed conversion using boost::any_cast
>>> extract = boost.any_cast[std.vector[int]](val) # correct cast
>>> type(extract) is std.vector[int]
True
>>> extract += xrange(100)
>>> len(extract)
100
>>> val.__assign__(std.move(extract)) # move forced
<cppyy.gbl.boost.any object at 0xf6a8a0>
>>> len(extract) # now empty (or invalid)
0
>>> extract = boost.any_cast[std.vector[int]](val)
>>> list(extract)
[0, 1, 2, 3, 4, 5, 6, ..., 97, 98, 99]
当然,没有理由从 Python 使用 Boost(实际上,这个例子需要 pythonizations),但它展示了 cppyy
无缝支持许多高级 C++ 特性。
cppyy
适用于 CPython(v2和v3)以及 PyPy,在后者中达到类似 C++ 的性能。它审慎使用预编译头、动态加载和延迟实例化,以支持由数百万行代码和数千个类组成的 C++ 程序。cppyy
最小化依赖关系,以便在分布式、异构开发环境中使用。