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 ) )
This is- and returns a list, of the enumerated factors. Is it
starting to get bulky.
import ext
extA= ext.Ext()
extA[ 'enumfactors' ]= r"""
#include <string>
#include <vector>
using namespace std;
PyObject* enumfactors( int a, const char* sep ) {
string fmt= "[";
vector< long > resv;
for( int i= 1; i<= a; i++ ) {
if( a% i== 0 ) {
resv.push_back( i );
fmt.append( "i" );
if( i> 1 ) {
printf( "%s", sep );
}
printf( "%i", i );
}
}
printf( "\n" );
fmt.append( "]" );
PyObject* res= PyList_New( resv.size() );
for( int i= 0; i< resv.size(); i++ ) {
PyObject* v= PyLong_FromLong( resv[i] );
int succ= PyList_SetItem( res, i, v );
}
return res;
}
""", ("O","i","s")
factorsn= extA.enumfactors( 209677683, ', ' )
print( factorsn )
This modification required:
compilercommand= 'c:/programs/mingw/bin/g++'
and
strctypes= { 'i': 'int', 's': 'const char*',
'O': 'PyObject*' }
The output is:
#include <c:/programs/python/include/Python.h>
[ user code ]
static PyObject *
extcode_enumfactors(PyObject *self, PyObject *args) {
PyObject* result;
int arg0;
const char* arg1;
PyArg_ParseTuple(args, "is", &arg0, &arg1 );
result= enumfactors( arg0, arg1 );
return Py_BuildValue( "O", result );
}
static PyMethodDef ExtcodeMethods[] = {
{ "enumfactors", extcode_enumfactors, METH_VARARGS, "" },
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initextcode(void) {
(void) Py_InitModule("extcode", ExtcodeMethods);
}
The benefits are automatic parameter parsing and automatic method
table construction. The costs are portability and parameter parsing
flexibility. Add up.