为 Python 写一个 C++ 扩展模块( 二 )

MyClass创建一个 Python docs.python.org 定义 。一个堆类型对应于一个 Python 类,然后将它赋值给MyModule模块 。
注意,如果其中一个函数返回失败,则必须减少以前创建的复制对象的引用计数,以便解释器删除它们 。
指定 Python 类型
MyClass详述在 github.com 中可以找到,它作为 docs.python.org 的一个实例:
 

  1.  
    static PyType_Spec spec_myclass = {
     
  2.  
    "MyClass", // name
     
  3.  
    sizeof(MyClassObject) + sizeof(MyClass), // basicsize
     
  4.  
    0, // itemsize
     
  5.  
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // flags
     
  6.  
    MyClass_slots // slots
     
  7.  
    };
     
 
它定义了一些基本类型信息,它的大小包括 Python 表示的大小(MyClassObject)和普通 C++ 类的大小(MyClass) 。MyClassObject定义如下:
 
  1.  
    typedef struct {
     
  2.  
    PyObject_HEAD
     
  3.  
    int m_value;
     
  4.  
    MyClass* m_myclass;
     
  5.  
    } MyClassObject;
     
 
Python 表示的话就是 docs.python.org 类型,由PyObject_HEAD宏和其他一些成员定义 。成员m_value视为普通类成员,而成员m_myclass只能在 C++ 代码内部访问 。
docs.python.org 定义了一些其他功能:
 
  1.  
    static PyType_Slot MyClass_slots[] = {
     
  2.  
    {Py_tp_new, (void*)MyClass_new},
     
  3.  
    {Py_tp_init, (void*)MyClass_init},
     
  4.  
    {Py_tp_dealloc, (void*)MyClass_Dealloc},
     
  5.  
    {Py_tp_members, MyClass_members},
     
  6.  
    {Py_tp_methods, MyClass_methods},
     
  7.  
    {0, 0} /* Sentinel */
     
  8.  
    };
     
 
在这里,设置了一些初始化和析构函数的跳转,还有普通的类方法和成员,还可以设置其他功能,如分配初始属性字典,但这是可选的 。这些定义通常以一个哨兵结束,包含NULL值 。
要完成类型详述,还包括下面的方法和成员表:
 
  1.  
    static PyMethodDef MyClass_methods[] = {
     
  2.  
    {"addOne", (PyCFunction)MyClass_addOne, METH_NOARGS, PyDoc_STR("Return an incrmented integer")},
     
  3.  
    {NULL, NULL} /* Sentinel */
     
  4.  
    };
     
  5.  
     
  6.  
    static struct PyMemberDef MyClass_members[] = {
     
  7.  
    {"value", T_INT, offsetof(MyClassObject, m_value)},
     
  8.  
    {NULL} /* Sentinel */
     
  9.  
    };
     
 
在方法表中,定义了 Python 方法addOne,它指向相关的 C++ 函数MyClass_addOne 。它充当了一个包装器,它在 C++ 类中调用addOne()方法 。
在成员表中,只有一个为演示目的而定义的成员 。不幸的是,在 docs.python.org 中使用的 en.cppreference.com 不允许添加 C++ 类型到MyClassObject 。如果你试图放置一些 C++ 类型的容器(如 en.cppreference.com),编译器会抱怨一些内存布局相关的警告 。
初始化和析构
MyClass_new方法只为MyClassObject提供一些初始值,并为其类型分配内存:


推荐阅读