# 从头开始实现一个线性代数库：Python模块篇

``In [1]: ls``linalg.cpython-36m-darwin.so*``In [2]: import linalg``In [3]: m = linalg.Matrix([``   ...:     [43, 63, 57, 35],``   ...:     [63, 26, 32, 35],``   ...:     [57, 32, 78, 76],``   ...:     [35, 35, 76, 25],``   ...: ])``In [4]: m.Jacobi()``Out[4]: C(-19.248723 33.225382 197.775875 -39.752533)``In [5]: m.det()``Out[5]: 5028170.999999999``

## 定义模块

``static PyModuleDef linalgmodule = {``    PyModuleDef_HEAD_INIT,``    "linalg",   /* name of module */``    NULL,        /* module documentation, may be NULL */``    -1,            /* size of per-interpreter state of the module,``                 or -1 if the module keeps state in global variables. */``};``

``PyMODINIT_FUNC``PyInit_linalg(void) {``    PyObject *m;``    m = PyModule_Create(&linalgmodule);``    if (m == NULL) return NULL;``    // 添加Vector/Matrix类``    if (PyType_Ready(&PyVectorType) < 0) return NULL;``    if (PyType_Ready(&PyMatrixType) < 0) return NULL;``    Py_INCREF(&PyVectorType);``    Py_INCREF(&PyMatrixType);``    PyModule_AddObject(m, "Vector", (PyObject*)&PyVectorType);``    PyModule_AddObject(m, "Matrix", (PyObject*)&PyMatrixType);``    return m;``}``

## 定义`linalg.Vector`类

``typedef struct {``    PyObject_HEAD;``    Vector ob_vector; // 需要封装的成员``} PyVectorObject;``

``static PyTypeObject PyVectorType = {``    PyObject_HEAD_INIT(NULL)``    .tp_name = "linalg.Vector", // 模块类名``    .tp_doc = "Vector objects", // doc描述``    .tp_basicsize = sizeof(PyVectorObject), // 对象大小``    .tp_itemsize = 0,``    .tp_dealloc = (destructor) PyLinAlg_dealloc, // 析构函数``    .tp_new = PyType_GenericNew, // 构造函数``    .tp_init = (initproc) PyVector_init, // 初始化函数``    .tp_members = PyVector_members, // 类成员``    .tp_methods = PyVector_methods, // 类方法``    .tp_flags = Py_TPFLAGS_DEFAULT,``    .tp_str = (reprfunc)PyVector_str, // str(obj), print用``    .tp_repr = (reprfunc)PyVector_str,``    .tp_as_sequence = &PyVectorSeq_methods, // 一些序列类方法，例如vec[i]``    .tp_as_number = &PyVectorNum_methods, // 基本运算方法，例如vecA + vecB``};``

``static void``PyLinAlg_dealloc(PyObject *self) {``    Py_TYPE(self)->tp_free((PyObject *)self);``}``

``Vector v({16,22,32,44});``v.show();``

``In [6]: v = linalg.Vector([1,2,3,4])``In [7]: v``Out[7]: C(1.000000 2.000000 3.000000 4.000000)``

``static int``PyVector_init(PyVectorObject *self, PyObject *args, PyObject *kwds) {``    PyObject *pList, *pItem;``    if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &pList)) { // 初始化参数必须为列表``        PyErr_SetString(PyExc_TypeError, "parameter must be a list.");``        return -1;``    } ``    Py_ssize_t n = PyList_Size(pList); // 获取列表长度``    if(n <= 0) {``        PyErr_SetString(PyExc_TypeError, "size of list must be greater than 0");``        return -1;``    }``    vector<double> data;``    for(Py_ssize_t i = 0; i < n; ++i) {``        pItem = PyList_GetItem(pList, i);``        if(! isNumber(pItem))  return -1; // 列表内的元素必须为数字``        else data.push_back(getNumber(pItem));``    }``    self->ob_vector = Vector(data); // 存入封装Vector的VectorObject类型中``    return 0;``}``

``static PyMethodDef PyVector_methods[] = {``    {"T", (PyCFunction)PyVector_T, METH_NOARGS, "change vector type"},``    {"copy", (PyCFunction)PyVector_Copy, METH_NOARGS, "deep copy of vector"},``    {NULL}  /* Sentinel */``};``

### 引用计数导致的BUG

``static PyObject *``PyVector_imul(PyVectorObject *self, PyObject *arg) {``    if(!arg || ! isNumber(arg)) return NULL;``    Py_XINCREF(self); // 不加这个会崩溃...因为返回的对象没有被接收会被释放掉``    self->ob_vector *= getNumber(arg);``    return (PyObject*)self;``}``

Return value: New reference.
Returns the result of adding o1 and o2, or NULL on failure. The operation is done in-place when o1 supports it. This is the equivalent of the Python statement o1 += o2.

According to the documentation, the inplace add operation for an object returns a new reference.
By returning self directly without calling Py_INCREF on it, your object will be freed while it is still referenced. If some other object is allocated the same piece of memory, those references would now give you the new object.

## 编译、链接模块

``from distutils.core import setup, Extension``linalgmodule = Extension('linalg',``        extra_compile_args = ['-std=c++14'],``        sources = ['src/linalgmodule.cpp'],``        include_dirs = ['include'],``        libraries = ['linalg'],``        )``setup (name = 'linalg',``        version = '0.1',``        author = 'netcan',``        author_email = 'netcan1996@gmail.com',``        description = 'A Linear Algebra library for studying by netcan',``        ext_modules = [linalgmodule],``        )``

`` python setup.py build``

``CFLAGS='-I/Library/Developer/CommandLineTools/usr/include/c++/v1/' python setup.py build``

1. 1. 定义模块
2. 2. 定义linalg.Vector类
3. 3. 编译、链接模块