f2py does not output inout as expected

77 views Asked by At

Why does f2py not generate a correct wrapper when dealing with inout params?

Here is an example of my function call:

io = 7.5
io, out1, out2, out3 = fortran_file.func(5, 2.5, False, io)

Here's how that might look in Fortran (example.f):

subroutine func(inputA, inputB, inputC, ioD, outE, outF, outG)

integer inputA
real inputB
logical inputC

real ioD, outE, outF, outG
real localH

if(.not.inputC) then
   localH= ioD
else
   localH= inputB
endif

ioD= ioD + localH
outE= inputA + 10.5
outF= inputA + 5.5
outG= inputA + 1.5
return
end

By default f2py marks everything here as an input, even though this is a basic example. So I create the file signature using:

python.exe -m numpy.f2py -m fortran_file -h sig_example.pyf example.f

I edit the pyf file to add the correct intent info. Then I compile using:

python.exe -m numpy.f2py -c sig_example.pyf example.f

But it keeps complaining that the f2py func only returns 3 items.

Even with io explicitly using intent(inout), f2py doesn't return it.

I used the --build-dir option in f2py to look at the generated C code for the wrapper. The file lists io under Parameters, but it says in/output rank-0 array(float,'f) This tells me it knows it's supposed to be inout, but I don't get why its labeling it an array? It also doesn't list io under "Returns" which just makes me even more confused. The associated Py_BuildValue call also doesn't include io in the list of args.

Why does it seem like inout isn't supposed to be returned? That's the whole point of inout, and for certain files it's required.

I realize this whole question is niche, but I could really use some help here. Is there a way to specify param intents inside of Python? Because I have too many files to manually edit signatures.

1

There are 1 answers

6
Vladimir F Героям слава On

An intent(inout) argument will work in a similar way it does in Fortran. However, in Python the values of the variables in the Python environment are immutable. The Fortran function will receive a copy, it will modify it's copy and then the modified copy will be discarded by Python.

But a mutable value can be put into a container such as a NumPy array. That means

import numpy as np
io = np.asarray([7.5])
out, out, out = fortran_file.func(5, 2.5, False, io)
print(io)

will print

[15.]

with the new value modified by the function.