A Simple Example
-
The C extension interface is specific to CPython, and extension modules do not work on other Python implementations.
- 使用ctypes或者cffi有更好的可移植性
-
An important convention throughout the Python interpreter is the following: when a function fails, it should set an exception condition and return an error value (usually a NULL pointer). Exceptions are stored in a static global variable inside the interpreter; if this variable is NULL no exception has occurred. A second global variable stores the “associated value” of the exception (the second argument to raise). A third variable contains the stack traceback in case the error originated in Python code. These three variables are the C equivalents of the result in Python of sys.exc_info() (see the section on module sys in the Python Library Reference). It is important to know about them to understand how errors are passed around.
-
几个常见的错误函数
- PyErr_SetString()
- PyErr_SetFromErrno()
- PyErr_SetObject()
- PyErr_Occurred()
- PyErr_Clear()
- You don’t need to Py_INCREF() the objects passed to any of these functions.
-
malloc 之类的函数内存分配失败时必须调用 PyErr_NoMemory(),所有的对象创建函数比如PyLong_FromLong()等是这样实现的
-
除掉一些 PyArg_ParseTuple() 之类的函数,函数返回值是>=0成功,<0失败,和unix保持一致
-
be careful to clean up garbage (by making Py_XDECREF() or Py_DECREF() calls for objects you have already created) when you return an error indicator!
-
错误类型不要瞎报
-
可以自定义模块异常
-
When a function f that calls another function g detects that the latter fails, f should itself return an error value (usually NULL or -1). It should not call one of the PyErr_() functions — one has already been called by g. f’s caller is then supposed to also return an error indication to its caller, again without calling PyErr_(), and so on — the most detailed cause of the error was already reported by the function that first detected it.
- 这也是PyArg_ParseTuple()失败直接返回NULL的原因,PyArg_ParseTuple()会自己触发异常
- 可以发现 return NULL 和 PyErr 哥俩好
-
If you have a C function that returns no useful argument (a function returning void), the corresponding Python function must return None. You need this idiom to do so (which is implemented by the Py_RETURN_NONE macro):
Py_INCREF(Py_None); return Py_None;
-
Note the third entry (METH_VARARGS). This is a flag telling the interpreter the calling convention to be used for the C function. It should normally always be METH_VARARGS or METH_VARARGS | METH_KEYWORDS;
-
The METH_KEYWORDS 需要用PyArg_ParseTupleAndKeywords()
-
When the Python program imports module spam for the first time, PyInit_spam() is called.
-
When embedding Python, the PyInit_spam() function is not called automatically unless there’s an entry in the PyImport_Inittab table. To add the module to the initialization table, use PyImport_AppendInittab().
Calling Python Functions from C
-
This function must be registered with the interpreter using the METH_VARARGS flag
-
The macros Py_XINCREF() and Py_XDECREF() increment/decrement the reference count of an object and are safe in the presence of NULL pointers
-
Later, when it is time to call the function, you call the C function PyObject_CallObject(). This function has two arguments, both pointers to arbitrary Python objects: the Python function, and the argument list. The argument list must always be a tuple object, whose length is the number of arguments. To call the Python function with no arguments, pass in NULL, or an empty tuple; to call it with one argument, pass a singleton tuple. Py_BuildValue() returns a tuple when its format string consists of zero or more format codes between parentheses.
-
The return value of PyObject_CallObject() is “new”: either it is a brand new object, or it is an existing object whose reference count has been incremented. So, unless you want to save it in a global variable, you should somehow Py_DECREF() the result, even (especially!) if you are not interested in its value.
- PyObject_CallObject()的返回值如果你不需要的话应该Py_DECREF(),但是需要对返回值做NULL判定,所以可以用Py_XDECREF()
Extracting Parameters in Extension Functions
-
PyArg_ParseTuple()的参数类型必须对上,对不上可能导致崩溃或者其他未定义行为
-
Note that any Python object references which are provided to the caller are borrowed references; do not decrement their reference count!
-
int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict, const char *format, char *kwlist[], …);
-
kwlist参数是以NULL结尾的字符串列表
-
PyArg_ParseTupleAndKeywords()使用关键字参数时无法解析嵌套的元组!传入的关键字参数不在kwlist中,这将导致引发TypeError。
-
Py_BuildValue的参数只能是值不能是指针
Reference Counts
- Py_DECREF() also frees the object when the count reaches zero. For flexibility, it doesn’t call free() directly — rather, it makes a call through a function pointer in the object’s type object. For this purpose (and others), every object also contains a pointer to its type object.
- Nobody “owns” an object; however, you can own a reference to an object.
- The owner of a reference is responsible for calling Py_DECREF() when the reference is no longer needed. Ownership of a reference can be transferred. There are three ways to dispose of an owned reference: pass it on, store it, or call Py_DECREF(). Forgetting to dispose of an owned reference creates a memory leak.
- It is also possible to borrow [2] a reference to an object. The borrower of a reference should not call Py_DECREF(). The borrower must not hold on to the object longer than the owner from which it was borrowed. Using a borrowed reference after the owner has disposed of it risks using freed memory and should be avoided completely [3].
- The advantage of borrowing over owning a reference is that you don’t need to take care of disposing of the reference on all possible paths through the code — in other words, with a borrowed reference you don’t run the risk of leaking when a premature exit is taken. The disadvantage of borrowing over owning is that there are some subtle situations where in seemingly correct code a borrowed reference can be used after the owner from which it was borrowed has in fact disposed of it.
- A borrowed reference can be changed into an owned reference by calling Py_INCREF(). This does not affect the status of the owner from which the reference was borrowed — it creates a new owned reference, and gives full owner responsibilities (the new owner must dispose of the reference properly, as well as the previous owner).
Ownership Rules
- Whenever an object reference is passed into or out of a function, it is part of the function’s interface specification whether ownership is transferred with the reference or not.
- Most functions that return a reference to an object pass on ownership with the reference. In particular, all functions whose function it is to create a new object, such as PyLong_FromLong() and Py_BuildValue(), pass ownership to the receiver.
- Many functions that extract objects from other objects also transfer ownership with the reference, for instance PyObject_GetAttrString().
- PyTuple_GetItem(), PyList_GetItem(), PyDict_GetItem(), and PyDict_GetItemString() all return references that you borrow from the