C function in a Python context

castironpi at gmail.com castironpi at gmail.com
Sat Feb 9 22:04:44 CET 2008


On Feb 9, 1:48 pm, castiro... at gmail.com wrote:
> To write quick C things that Python won't do up to speed.  So it's got
> a redundancy.
>
> import ext
> extA= ext.Ext()
> extA[ 'enumfactors' ]= r"""
>     int enumfactors( int a, const char* sep ) {
>         int ret= 0, i;
>         for( i= 1; i<= a; i++ ) {
>             if( a% i== 0 ) {
>                 ret+= 1;
>                 if( i> 1 ) {
>                     printf( "%s", sep );
>                 }
>                 printf( "%i", i );
>             }
>         }
>         printf( "\n" );
>         return ret;
>     }
>     """, ("i","i","s")
>
> factorsn= extA.enumfactors( 209677683, ', ' )
> print( "%i factors total."% factorsn )
>
> import sys
> sys.exit()
>
> 1, 3, 23, 69, 131, 393, 3013, 9039, 23197, 69591, 533531, 1600593,
> 3038807, 9116
> 421, 69892561, 209677683
> 16 factors total.

'''Prototype implementation, slightly rigid.  If anyone knows how to
compile and link without intermediate object file, and from a string,
memory, or stdin, let me know.  Change first four lines.  If you are
not using gcc, look at regenpyd().'''

compilercommand=    'c:/programs/mingw/bin/gcc'
pythondll=          'python30'
pythonpathinclude=  'c:/programs/python/include'
pythonpathlibs=     'c:/programs/python/libs'

class Ext:
    strctypes= { 'i': 'int', 's': 'const char*' }
    class ExtElem:
        def __init__( self, name, code, types ):
            self.name, self.code= name, code
            self.types= types
    def __init__( self ):
        self.__dict__[ 'exts' ]= []
    def regenc( self ):
        extcode= open( 'extcode.c', 'w' )
        wr= extcode.write
        wr( '#include <%s'% pythonpathinclude )
        wr( '/Python.h>\n\n' )
        for ext in self.exts:
            wr( ext.code )
            wr( '\n' )
        for ext in self.exts:
            wr( 'static PyObject *\n' )
            wr( 'extcode_%s'% ext.name )
            wr( '(PyObject *self, ' )
            wr( 'PyObject *args) {\n' )
            wr( '\t%s result;\n'%
                Ext.strctypes[ext.types[0]] )
            for i, type in enumerate( ext.types[1:] ):
                wr( '\t%s arg%i;\n'%
                    ( Ext.strctypes[type], i ) )
            wr( '\tPyArg_ParseTuple(args, "' )
            wr( ''.join( ext.types[1:] ) )
            wr( '"' )
            for i, type in enumerate( ext.types[1:] ):
                wr( ', &arg%i'% i )
            wr( ' );\n' )
            wr( '\tresult= %s( '% ext.name )
            wr( ', '.join( [ 'arg%i'% i for i
                in range( len( ext.types[1:] ) ) ] ) )
            wr( ' );\n' )
            wr( '\treturn Py_BuildValue' )
            wr( '( "%s", result );\n'% ext.types[0] )
            wr( '}\n\n' )
        wr( 'static PyMethodDef ExtcodeMethods[] = {\n' )
        for ext in self.exts:
            wr( '\t{ "%s", extcode_%s, '%
                            ( ext.name, ext.name ) )
            wr( 'METH_VARARGS, "" },\n' )
        wr( '\t{NULL, NULL, 0, NULL}\n' )
        wr( '};\n\n' )
        wr( 'PyMODINIT_FUNC\n' )
        wr( 'initextcode(void) {\n' )
        wr( '\t(void) Py_InitModule' )
        wr( '("extcode", ExtcodeMethods);\n' )
        wr( '}\n\n' )
        extcode.close()
    def regenpyd( self ):
        import os, os.path
        if os.path.exists( 'extcode.pyd' ):
            os.remove( 'extcode.pyd' )
        import subprocess
        retcompile= subprocess.call(
            '%s extcode.c -c -I%s'%
            ( compilercommand, pythonpathinclude ) )
        assert not retcompile, 'Compiler error'
        retlink= subprocess.call(
            '%s -shared extcode.o -o extcode.pyd -L%s -l%s'
            % ( compilercommand, pythonpathlibs,
            pythondll ) )
        assert not retlink, 'Linker error'
        os.remove( 'extcode.o' )
        os.remove( 'extcode.c' )
    def __setitem__( self, key, value ):
        code, types= value
        self.exts.append( Ext.ExtElem( key, code, types ) )
        self.regenc()
        self.regenpyd()
        import extcode
        setattr( self, key, getattr( extcode, key ) )



More information about the Python-list mailing list