| 
      
      
      From: Ken S. <ksi...@tt...> - 2001-08-29 18:34:54
       | 
| > Inspired by the recent discussion of perls inline
> module I wrote the attached module, which is yet
> another way to do it.
Thanks for posting your solution, Thomas. I have added another example
(example4.py) which steals your Fibonacci function and demonstrates how
you can add Inlined C methods to a Python class.
I also just added (but have not yet committed into CVS) a build() method
to the PyInline class, which simplifies and abstracts the build process.
e.g.,
import PyInline, __main__
PyInline.build(code=r"""
#include <stdio.h>
void ja(char *str) {
  printf("Just another %s hacker\n", str);
}
""",
               targetmodule=__main__,
               language = 'C')
ja("Inline")
TTUL
Ken
> Thomas
>
> ----inline.py---
> class C_Func:
>     def __init__(self, inline, name, code, doc, prefix):
>         self.name = name
>         self.code = code
>         self.doc = doc
>         self.module = inline
>         self.prefix = prefix
>
>     def create(self, file):
>         file.write("static  PyObject *%s(PyObject *self, PyObject *args)\n"\
>                    % (self.prefix + self.name))
>         file.write(self.code)
>         file.write("\n");
>
>     def __call__(self, *args, **kw):
>         mod = self.module.create()
>         func = getattr(mod, self.name)
>         return func(*args, **kw)
>
> class Inline:
>     def __init__(self, name):
>         self.name = name
>         self.functions = {}
>         self.mod = None
>         self.libraries = []
>
>     def c_func(self, name, code, doc=None, prefix=''):
>         if self.mod:
>             raise RuntimeError, \
>                   "Cannot add any more functions: Extension already created"
>         func = C_Func(self, name, code, doc, prefix)
>         self.functions[name] = func
>         return func
>
>     def create(self):
>         if not self.mod:
>             # generate the code
>             import StringIO
>             buffer = StringIO.StringIO()
>             buffer.write("#include <python.h>\n")
>             buffer.write("\n")
>
>             for func in self.functions.values():
>                 func.create(buffer)
>
>             buffer.write("static PyMethodDef methods[] = {\n")
>             for fname in self.functions.keys():
>                 pre = self.functions[fname].prefix
>                 buffer.write('    { "%s", %s, METH_VARARGS },\n' % \
>                            (fname, pre + fname))
>             buffer.write('    { NULL }, /* sentinel */\n};\n')
>             buffer.write("\n")
>
>             buffer.write('void init%s(void)\n' % self.name)
>             buffer.write('{\n    Py_InitModule3("%s", methods, "");\n}\n' % \
>                          self.name)
>
>             code = buffer.getvalue()
>             buffer.close()
>
>             # calulate md5 digest
>             import md5
>             m = md5.new()
>             m.update(code)
>             hd = m.hexdigest()
>
>             # compare to existing digest, if present
>             try:
>                 old_md5 = open(self.name + '.md5', 'r').read()
>             except:
>                 old_md5 = None
>
>             # if the digests match, no recompilation is needed
>             if old_md5 != hd:
>                 # recompilation needed
>                 file = open(self.name + '.c', 'w')
>                 file.write(code)
>                 file.close()
>
>                 from distutils.core import setup, Extension
>
>                 ext = Extension(self.name, sources=[self.name + '.c'],
>                                 libraries=self.libraries)
>
>                 setup(ext_modules=[ext], script_name="dummy",
>                       script_args=["-q", "install", "--install-platlib=."])
>
>                 open(self.name + '.md5', 'w').write(hd)
>                 import os
>                 os.remove(self.name + '.c')
>
>             # import module
>             self.mod = __import__(self.name)
>
>     def __getattr__(self, name):
>         if name not in self.functions.keys():
>             raise AttributeError, name
>         if not self.mod:
>             self.create()
>         return getattr(self.mod, name)
>
> if __name__ == '__main__':
>     module = Inline("_sample")
>
>     # define a function implemented in C
>     # The function declaration will be added automatically,
>     # in this case 'static PyObject *fib_c(PyObject *self, PyObject *args)'
>     module.c_func("fib_c", r"""
> {
>     int i;
>     static int _fib(int);
>     if (!PyArg_ParseTuple(args, "i", &i))
>         return NULL;
>     return Py_BuildValue("i", _fib(i));
> }
>
> static int _fib(int i)
> {
>     if (i <= 2)
>         return i;
>     return _fib(i - 1) + _fib(i - 2);
> }
>     """)
>
>
>     # define a function implemented in C
>     # The function declaration will be added automatically,
>     # in this case 'static PyObject *fib_c(PyObject *self, PyObject *args)'
>     module.c_func("fact_c", r"""
> {
>     int i;
>     PyObject *inst;
>     static int _fact(int);
>     if (!PyArg_ParseTuple(args, "Oi", &inst, &i))
>         return NULL;
>     return Py_BuildValue("i", _fact(i));
> }
>
> static int _fact(int i)
> {
>     if (i <= 1)
>         return i;
>     return i * _fact(i - 1);
> }
>     """)
>
>
>
>     # generate and compile an extension module (if needed),
>     # retrieve the function from it.
>     fib_c = module.fib_c
>
>
>     # a similar function implemented in Python
>     def fib_py(i):
>         if i <= 2:
>             return i
>         return fib_py(i-1) + fib_py(i-2)
>
>     # we can also define a class, and use the extension module's functions
>     # as instance methods
>     class X:
>         def fact_py(self, i):
>             if i <= 1:
>                 return i
>             return i * self.fact_py(i-1)
>
>     # convert the extension function into a unbound method
>     # and attach it to the class
>     import new
>     X.fact_c = new.instancemethod(module.fact_c, None, X)
>
>     # do a little benchmark
>     import time
>
>     start = time.clock()
>     print "fib_py(30) =", fib_py(30), "%s seconds" % (time.clock() - start)
>
>     start = time.clock()
>     print "fib_c(30) =", fib_c(30), "%s seconds" % (time.clock() - start)
>
>     x = X()
>
>     start = time.clock()
>     print "x.fact_py(12) =", x.fact_py(12), "%s seconds" % (time.clock() - start)
>
>     start = time.clock()
>     print "x.fact_c(12) =", x.fact_c(12), "%s seconds" % (time.clock() - start)
>
>
>
>
>
>
> _______________________________________________
> Pyinline-discuss mailing list
> Pyi...@li...
> http://lists.sourceforge.net/lists/listinfo/pyinline-discuss
>
 |