Arty Arty - 5 months ago 21x
Python Question

Transmission bytearray from Python to C and return it

I need fast processing of XOR bytearray,
In a variant on Python

for i in range(len(str1)): str1[i]=str1[i] ^ 55

works very slow

I wrote this module in C.
I know C language very badly, before I on it wrote nothing.

In a variant

PyArg_ParseTuple (args, "s", &str))

everything works as expected, but I need to use instead of s s* because elements can contain embeded null, but if I change s to s* when calling python crash

PyArg_ParseTuple (args, "s*", &str)) // crash

Maybe some beginner like me want to use my example as a start to write something of his own, so bring all the information to be used in this example on Windows.

Parsing arguments and building values on page


#include <Python.h>

static PyObject* fast_xor(PyObject* self, PyObject* args)
const char* str ;
int i;

if (!PyArg_ParseTuple(args, "s", &str))
return NULL;

for(i=0;i<sizeof(str);i++) {str[i]^=55;};
return Py_BuildValue("s", str);


static PyMethodDef fastxorMethods[] =
{"fast_xor", fast_xor, METH_VARARGS, "fast_xor desc"},


(void) Py_InitModule("fastxor", fastxorMethods);

import fastxor
a=fastxor.fast_xor("World") # it works with s instead s*
print a
a=fastxor.fast_xor("Wo\0rld") # It does not work with s instead s*


rem use
tiny_impdef.exe C:\Python26\python26.dll
tcc -shared test_xor.c python26.def -IC:\Python26\include -LC:\Python26\libs -ofastxor.pyd


You don't need build an extension module to do this quickly, you can use NumPy. But for your question, you need some c code like this:

#include <Python.h>
#include <stdlib.h> 

static PyObject * fast_xor(PyObject* self, PyObject* args)
    const char* str;
    char * buf;
    Py_ssize_t count;
    PyObject * result;
    int i;

    if (!PyArg_ParseTuple(args, "s#", &str, &count))
        return NULL;

    buf = (char *)malloc(count);

        buf[i]=str[i] ^ 55;

    result = Py_BuildValue("s#", buf, count);
    return result;

You can't change the content of string object, because string in Python is immutable. You can use "s#" to get the char * pointer and the buffer length.

If you can use NumPy:

In [1]: import fastxor

In [2]: a = "abcdsafasf12q423\0sdfasdf"

In [3]: fastxor.fast_xor(a)
Out[3]: 'VUTSDVQVDQ\x06\x05F\x03\x05\x047DSQVDSQ'

In [5]: import numpy as np

In [6]: (np.frombuffer(a, np.int8)^55).tostring()
Out[6]: 'VUTSDVQVDQ\x06\x05F\x03\x05\x047DSQVDSQ'

In [7]: a = a*10000

In [8]: %timeit fastxor.fast_xor(a)
1000 loops, best of 3: 877 us per loop

In [15]: %timeit (np.frombuffer(a, np.int8)^55).tostring()
1000 loops, best of 3: 1.15 ms per loop