C code:
#include <Python.h>
PyObject* make_getter_code() {
const char* code =
"def code(self):\n"
" try:\n"
" return self.args[1]\n"
" except IndexError:\n"
" return -1\n"
"code = property(code)\n"
"def message(self):\n"
" try:\n"
" return self.args[0]\n"
" except IndexError:\n"
" return ''\n"
"\n";
PyObject* d = PyDict_New();
PyObject* dict_globals = PyDict_New();
PyDict_SetItemString(dict_globals, "__builtins__", PyEval_GetBuiltins());
PyObject* output = PyRun_String(code,Py_file_input,dict_globals,d);
if (output==NULL) {
Py_DECREF(d);
return NULL;
}
Py_DECREF(output);
Py_DECREF(dict_globals);
return d;
}
static PyObject* MyLibraryError;
static PyObject* my_library_function(PyObject* self) {
/* something's gone wrong */
PyObject *tuple = PyTuple_New(2);
PyTuple_SetItem(tuple, 0, PyUnicode_FromString("Helpful error message"));
PyTuple_SetItem(tuple, 1, PyLong_FromLong(257));
PyErr_SetObject(MyLibraryError, tuple);
return NULL;
}
static PyMethodDef methods[] = {
{"my_library_function", my_library_function, METH_NOARGS,
"raise an error."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
static struct PyModuleDef librarymodule = {
PyModuleDef_HEAD_INIT,
"library", /* 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. */
methods
};
PyMODINIT_FUNC
PyInit_library(void) {
PyObject *m;
m = PyModule_Create(&librarymodule);
if (m == NULL)
return NULL;
PyObject* exc_dict = make_getter_code();
if (exc_dict == NULL) {
return NULL;
}
MyLibraryError = PyErr_NewException("library.MyLibraryError",
NULL, // use to pick base class
exc_dict);
PyModule_AddObject(m,"MyLibraryError",MyLibraryError);
return m;
}
As an example of the more elegant Python interface, your Python code changes to:
try:
my_library_func()
except MyLibraryError as ex:
message, code = ex.message, ex.code
This utility function prints a warning message to sys.stderr when an exception has been set but it is impossible for the interpreter to actually raise the exception. It is used, for example, when an exception occurs in an __del__() method.,This function is not normally used by code that wants to handle exceptions. Rather, it can be used when code needs to save and restore the exception state temporarily. Use PyErr_SetExcInfo() to restore or clear the exception state.,This function is not normally used by code that wants to handle exceptions. Rather, it can be used when code needs to save and restore the exception state temporarily. Use PyErr_GetExcInfo() to read the exception state.,The function is called with a single argument obj that identifies the context in which the unraisable exception occurred. If possible, the repr of obj will be printed in the warning message.
{
PyObject * type, * value, * traceback;
PyErr_Fetch( & type, & value, & traceback);
/* ... code that might produce other errors ... */
PyErr_Restore(type, value, traceback);
}
if (tb != NULL) { PyException_SetTraceback(val, tb); }
I've illustrated option 2, but I don't anycodings_python-3.x think there a huge reason to prefer one anycodings_python-3.x or the other.,However there are two options to make anycodings_python-3.x your exception class slightly more anycodings_python-3.x user-friendly on the Python side:,As an example of the more elegant Python anycodings_python-3.x interface, your Python code changes to:,The closest I can get to, which I don't anycodings_python-c-api like, is by using PyErr_SetObject
For example I want to do this in the Python anycodings_python-c-api layer:
try:
call_my_library_func()
except MyLibraryError as ex:
print("Error code was %s" % ex.code)
The closest I can get to, which I don't anycodings_python-c-api like, is by using PyErr_SetObject
PyObject * tuple = PyTuple_New(2);
PyTuple_SetItem(tuple, 0, PyUnicode_FromString("Helpful error message"));
PyTuple_SetItem(tuple, 1, PyLong_FromLong(257));
//PyErr_SetString(MyLibraryError, "Helpful error message\n");
PyErr_SetObject(MyLibraryError, tuple);
Then I can do this:
try:
call_my_library_func()
except MyLibraryError as ex:
message, code = ex.args[0], -1
if len(ex.args > 1):
code = ex.args[1]
C code:
#include <Python.h>
PyObject* make_getter_code() {
const char* code =
"def code(self):\n"
" try:\n"
" return self.args[1]\n"
" except IndexError:\n"
" return -1\n"
"code = property(code)\n"
"def message(self):\n"
" try:\n"
" return self.args[0]\n"
" except IndexError:\n"
" return ''\n"
"\n";
PyObject* d = PyDict_New();
PyObject* dict_globals = PyDict_New();
PyDict_SetItemString(dict_globals, "__builtins__", PyEval_GetBuiltins());
PyObject* output = PyRun_String(code,Py_file_input,dict_globals,d);
if (output==NULL) {
Py_DECREF(d);
return NULL;
}
Py_DECREF(output);
Py_DECREF(dict_globals);
return d;
}
static PyObject* MyLibraryError;
static PyObject* my_library_function(PyObject* self) {
/* something's gone wrong */
PyObject *tuple = PyTuple_New(2);
PyTuple_SetItem(tuple, 0, PyUnicode_FromString("Helpful error message"));
PyTuple_SetItem(tuple, 1, PyLong_FromLong(257));
PyErr_SetObject(MyLibraryError, tuple);
return NULL;
}
static PyMethodDef methods[] = {
{"my_library_function", my_library_function, METH_NOARGS,
"raise an error."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
static struct PyModuleDef librarymodule = {
PyModuleDef_HEAD_INIT,
"library", /* 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. */
methods
};
PyMODINIT_FUNC
PyInit_library(void) {
PyObject *m;
m = PyModule_Create(&librarymodule);
if (m == NULL)
return NULL;
PyObject* exc_dict = make_getter_code();
if (exc_dict == NULL) {
return NULL;
}
MyLibraryError = PyErr_NewException("library.MyLibraryError",
NULL, // use to pick base class
exc_dict);
PyModule_AddObject(m,"MyLibraryError",MyLibraryError);
return m;
}
As an example of the more elegant Python anycodings_python-3.x interface, your Python code changes to:
try:
my_library_func()
except MyLibraryError as ex:
message, code = ex.message, ex.code
Note that the C extension interface is specific to official CPython. It is likely that extension modules do not work on other Python implementations such as PyPy. Even if official CPython, the Python C API may be not compatible with different versions, e.g., Python2 and Python3. Therefore, if extension modules are considered to be run on other Python interpreters, it would be better to use ctypes module or cffi.,In order to call python function safely, we can simply warp Python Functions between PyGILState_Ensure and PyGILState_Release in C extension code.,Occasionally, it is unavoidable for pythoneers to write a C extension. For example, porting C libraries or new system calls to Python requires to implement new object types through C extension. In order to provide a brief glance on how C extension works. This cheat sheet mainly focuses on writing a Python C extension.,If threads are created from C/C++, those threads do not hold the GIL. Without acquiring the GIL, the interpreter cannot access Python functions safely. For example
from distutils.core
import setup, Extension
ext = Extension('foo', sources = ['foo.c'])
setup(name = "Foo", version = "1.0", ext_modules = [ext])
import sysconfig
from distutils.core
import setup, Extension
cflags = sysconfig.get_config_var("CFLAGS")
extra_compile_args = cflags.split()
extra_compile_args += ["-Wextra"]
ext = Extension(
"foo", ["foo.c"],
extra_compile_args = extra_compile_args
)
setup(name = "foo", version = "1.0", ext_modules = [ext])
PyDoc_STRVAR(doc_mod, "Module document\n");
PyDoc_STRVAR(doc_foo, "foo() -> None\n\nFoo doc");
static PyMethodDef methods[] = {
{
"foo",
(PyCFunction) foo,
METH_NOARGS,
doc_foo
},
{
NULL,
NULL,
0,
NULL
}
};
static struct PyModuleDef module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "Foo",
.m_doc = doc_mod,
.m_size = -1,
.m_methods = methods
};
#include <Python.h>
PyDoc_STRVAR(doc_mod, "Module document\n");
PyDoc_STRVAR(doc_foo, "foo() -> None\n\nFoo doc");
static PyObject* foo(PyObject* self)
{
PyObject* s = PyUnicode_FromString("foo");
PyObject_Print(s, stdout, 0);
Py_RETURN_NONE;
}
static PyMethodDef methods[] = {
{"foo", (PyCFunction)foo, METH_NOARGS, doc_foo},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT, "Foo", doc_mod, -1, methods
};
PyMODINIT_FUNC PyInit_foo(void)
{
return PyModule_Create(&module);
}
$ python setup.py - q build
$ python setup.py - q install
$ python - c "import foo; foo.foo()"
'foo'
#include <Python.h>
static PyObject* foo(PyObject* self)
{
Py_BEGIN_ALLOW_THREADS
sleep(3);
Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static PyMethodDef methods[] = {
{"foo", (PyCFunction)foo, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT, "Foo", NULL, -1, methods
};
PyMODINIT_FUNC PyInit_foo(void)
{
return PyModule_Create(&module);
}
Common customization features C/C++ helper functions Adding additional Python code Class extension with %extend Exception handling with %exception , %extend works with both C and C++ code. It does not modify the underlying object in any way---the extensions only show up in the Python interface. , If a C or C++ function throws an error, you may want to convert that error into a Python exception. To do this, you can use the %exception directive. %exception simply lets you rewrite part of the generated wrapper code to include an error check. , The language-independent exception.i library file can also be used to raise exceptions. See the SWIG Library chapter.
/* File: example.i */ %
module example
%
{
#define SWIG_FILE_WITH_INIT#include "example.h"
%
}
int fact(int n);
/* File: example.c */
#include "example.h"
int fact(int n) {
if (n < 0) {
/* This should probably return an error, but this is simpler */
return 0;
}
if (n == 0) {
return 1;
} else {
/* testing for overflow would be a good idea here */
return n * fact(n - 1);
}
}
/* File: example.h */
int fact(int n);
$ swig - python example.i
$ swig - c++ - python example.i
#!/usr/bin/env python "" " setup.py file for SWIG example "" " from distutils.core import setup, Extension example_module = Extension('_example', sources = ['example_wrap.c', 'example.c'], ) setup(name = 'example', version = '0.1', author = "SWIG Docs", description = "" "Simple swig example from docs" "", ext_modules = [example_module], py_modules = ["example"], )
disable class-based built-in exceptions (just use strings); obsolete starting with version 1.6,Merges (concatenates) the string representations of elements in sequence seq into a string, with separator string.,Python also allows you to create your own exceptions by deriving classes from the standard built-in exceptions.,The dir() built-in function returns a sorted list of strings containing the names defined by a module.
For example, if we want Python 3.x's integer division behavior in Python 2, add the following import statement.
from __future__
import division
Most notable and most widely known change in Python 3 is how the print function is used. Use of parenthesis () with print function is now mandatory. It was optional in Python 2.
print "Hello World" #is acceptable in Python 2 print("Hello World") # in Python 3, print must be followed by()
The print() function inserts a new line at the end, by default. In Python 2, it can be suppressed by putting ',' at the end. In Python 3, "end =' '" appends space instead of newline.
print x, # Trailing comma suppresses newline in Python 2 print(x, end = " ") # Appends a space instead of a newline in Python 3
Python 2 accepts both notations, the 'old' and the 'new' syntax; Python 3 raises a SyntaxError if we do not enclose the exception argument in parenthesis.
raise IOError, "file error"
#This is accepted in Python 2
raise IOError("file error") #This is also accepted in Python 2
raise IOError, "file error"
#syntax error is raised in Python 3
raise IOError("file error") #this is the recommended syntax in Python 3
In Python 3, arguments to exception should be declared with 'as' keyword.
except Myerror, err: # In Python2 except Myerror as err: #In Python 3
When you write C extensions, you need to be aware that errors can occur on either side of the languages fence. The following sections address both possibilities. ,Pass in the address of a char* for s codes when converting to C, not the address of a char array: Python copies out the address of an existing C string (and you must copy it to save it indefinitely on the C side: use strdup). ,In fact, there is little to distinguish hello as a C extension module at all, apart from its filename. Python code imports the module and fetches its attributes as if it had been written in Python. C extension modules even respond to dir calls as usual, and have the standard module and filename attributes (though the filename doesn end in a .py or .pyc this time around): , When you add new or existing C components to Python, you need to code an interface (or "glue") logic layer in C that handles cross-language dispatching and data translation. The C source file in Example 19-1 shows how to code one by hand. It implements a simple C extension module named hello for use in Python scripts, with a function named message that simply returns its input string argument with extra text prepended.
Example 19-1. PP2EIntegrateExtendHellohello.c
/********************************************************************
* A simple C extension module for Python, called "hello"; compile
* this into a ".so" on python path, import and call hello.message;
********************************************************************/
#include
#include
/* module functions */
static PyObject * /* returns object */
message(PyObject * self, PyObject * args) /* self unused in modules */ {
/* args from python call */
char * fromPython, result[64];
if (!PyArg_Parse(args, "(s)", & fromPython)) /* convert Python -> C */
return NULL; /* null=raise exception */
else {
strcpy(result, "Hello, "); /* build up C string */
strcat(result, fromPython); /* add passed Python string */
return Py_BuildValue("s", result); /* convert C -> Python */
}
}
/* registration table */
static struct PyMethodDef hello_methods[] = {
{
"message",
message,
1
},
/* method name, C func ptr, always-tuple */ {
NULL,
NULL
} /* end of table marker */
};,
/* module initializer */
void inithello() /* called on first import */ {
/* name matters if loaded dynamically */
(void) Py_InitModule("hello", hello_methods); /* mod name, table ptr */
}
Example 19-2. PP2EIntegrateExtendHellomakefile.hello
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Compile hello.c into a shareable object file on Linux, # to be loaded dynamically when first imported by Python. # MYPY is the directory where your Python header files live. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # PY = $(MYPY) hello.so: hello.c gcc hello.c - g - I$(PY) / Include - I$(PY) - fpic - shared - o hello.so clean: rm - f hello.so core
Finally, to call the C function from a Python program, simply import module hello and call its hello.message function with a string:
[mark @toy~/.../PP2E / Integrate / Extend / Hello] $ make - f makefile.hello [mark @toy~/.../PP2E / Integrate / Extend / Hello] $ python >>> import hello # import a C module >>> hello.message(world) # call a C function Hello, world >>> hello.message(extending) Hello, extending
Example 19-3. PP2EIntegrateExtendHellohellouse.py
import hello
print hello.message(C)
print hello.message(module + hello.__file__)
for i in range(3):
print hello.message(str(i))
Run this script as any other -- when the script first imports module hello, Python automatically finds the C modules .so object file in a directory on PYTHONPATH and links it into the process dynamically. All of this scripts output represents strings returned from the C function in file hello.c :
[mark @toy~/.../PP2E / Integrate / Extend / Hello] $ python hellouse.py
Hello, C
Hello, module. / hello.so
Hello, 0
Hello, 1
Hello, 2