[SciPy-user] Vectorize wrapped Fortran routine

Pearu Peterson pearu at scipy.org
Fri Apr 7 12:19:41 CDT 2006



On Fri, 7 Apr 2006, steffen.loeck at gmx.de wrote:

> Hi,
>
> I would like to vectorize a Fortran routine wrapped with f2py using
> scipy.vectorize. With the old scipy this works fine but with the new one i
> get the following error:
>
> TypeError: object is not a callable Python object
>
> Wrapping was done with:
>
> f2py -m hermite -h hermite.pyf hermite.f
> f2py2.3  -c hermite.pyf  hermite.f
>
> The routine works without using vectorize but scipy.vectorize(hermite.routine)
> fails.
>
> Is there any way to get this working under new scipy?

vectorize expects a Python function or method as a first argument as this 
assumption allows it to determine the number of expected arguments.
As a workaround, you can use
   scipy.vectorize(lambda x:hermite.routine(x))
(the number of x-es may vary in your case).

However, the error is misleading. For example, f2py generated fortran 
objects and instances of a class with __call__ method are callable 
according to callable(<obj>) test but fail in vectorize.

As a possible fix, here is a more general way to determine the number of 
arguments of a callable Python object:

# File: test_nargs.py
import re
import types

def get_nargs(obj):
     if not callable(obj):
         raise TypeError, 'object is not a callable Python object: 
'+str(type(obj))
     if hasattr(obj,'func_code'):
         fcode = obj.func_code
         nargs = fcode.co_argcount
         if obj.func_defaults is not None:
             nargs -= len(obj.func_defaults)
         if isinstance(obj, types.MethodType):
             nargs -= 1
         return nargs
     terr = re.compile(r'.*? takes exactly (?P<exargs>\d+) argument(s|) 
\((?P<gargs>\d+) given\)')
     try:
         obj()
         return 0
     except TypeError, msg:
         m = terr.match(str(msg))
         if m:
             nargs = int(m.group('exargs'))-int(m.group('gargs'))
             if isinstance(obj, types.MethodType):
                 nargs -= 1
             return nargs
     raise ValueError, 'failed to determine the number of arguments for %s' 
% (obj)

# TEST CODE FOLLOWS:

class A:

     def foo(self, a1, a2, a3):
         pass

     def __call__(self, a1, a2):
         pass

     def car(self, a1, a2=2):
         pass

def bar(a1,a2,a3,a4):
     pass

def gun(a1,a2,a3=1,a4=2):
     pass

from numpy.testing import *
assert_equal(get_nargs(A()),2)
assert_equal(get_nargs(A().foo),3)
assert_equal(get_nargs(A().car),1)
assert_equal(get_nargs(bar),4)
assert_equal(get_nargs(gun),2)

import t
# t is f2py generated module using a command:
# f2py -c foo.f -m t
# where foo.f contains:
"""
       subroutine sin(x,r)
       double precision x,r
cf2py intent(out) r
       r = dsin(x)
       end
"""
assert_equal(get_nargs(t.sin),1)

#EOF



More information about the SciPy-user mailing list