首页 \ 问答 \ 使用Ctypes从Python调用Fortran时返回数组(Returning array when calling Fortran from Python using Ctypes)

使用Ctypes从Python调用Fortran时返回数组(Returning array when calling Fortran from Python using Ctypes)

如何使用ctypes将数组从Fortran返回到Python?

举个例子,我将一个数组(长度为5)从Python传递给Fortran。 使用相同的值创建输出数组。 然后,它被传递回Python。 在Fortran中,值是正确的,但在被发送回Python之后,它们不是。 我的设置怎么样不允许数组正确传递?

我的Fortran代码(例如,test.f)包含以下内容:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C)

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray

print *, "outArray from within Fortran"
do i = 1, lenInOut
  outArray(i) = inArray(i)
  print *, outArray(i)
end do
return
end subroutine mySub

这被编译为.so:

ifort -g -O0 -fpic -traceback -c -o "test.o" "../test.f"
ifort -shared -o "mylib.so"  ./test.o

Python代码如下:

from ctypes import *

mylib = CDLL('mylib.so')

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = IntType(5)
inputoutput = ArrayType(0,0,0,0,0)              

mylib.mySub.argtypes = [ArrayType,IntType,ArrayType]
mylib.mySub.restype =  ArrayType

output = mylib.mySub(input1,input2,inputoutput)

print '------------------------------------------------------'  
print 'output within Python'
print output
a = [0,1,2,3,4]
for ii in a: print output[ii]

输出结果如下:

#outArray from within Fortran
#1.10000000000000     
#2.20000000000000     
#3.30000000000000     
#4.40000000000000     
#5.50000000000000     
#------------------------------------------------------
#output within Python
#<__main__.c_double_Array_5 object at 0x10aa830>
#2.96439387505e-323
#6.91177308417e-310
#1.48219693752e-323
#6.91177308238e-310
#6.91177319086e-310

How do you return arrays from Fortran to Python using ctypes?

As an example, I pass in an array (length 5) from Python to Fortran. An output array is created with the same values. Then, it is passed back to Python. Within Fortran, the values are correct, but after being sent back to Python, they are not. What about my setup is not allowing the array to pass correctly?

My Fortran code (e.g., test.f) contains the following:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C)

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray

print *, "outArray from within Fortran"
do i = 1, lenInOut
  outArray(i) = inArray(i)
  print *, outArray(i)
end do
return
end subroutine mySub

This is compiled as a .so:

ifort -g -O0 -fpic -traceback -c -o "test.o" "../test.f"
ifort -shared -o "mylib.so"  ./test.o

Python code is as follows:

from ctypes import *

mylib = CDLL('mylib.so')

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = IntType(5)
inputoutput = ArrayType(0,0,0,0,0)              

mylib.mySub.argtypes = [ArrayType,IntType,ArrayType]
mylib.mySub.restype =  ArrayType

output = mylib.mySub(input1,input2,inputoutput)

print '------------------------------------------------------'  
print 'output within Python'
print output
a = [0,1,2,3,4]
for ii in a: print output[ii]

The output gives the following:

#outArray from within Fortran
#1.10000000000000     
#2.20000000000000     
#3.30000000000000     
#4.40000000000000     
#5.50000000000000     
#------------------------------------------------------
#output within Python
#<__main__.c_double_Array_5 object at 0x10aa830>
#2.96439387505e-323
#6.91177308417e-310
#1.48219693752e-323
#6.91177308238e-310
#6.91177319086e-310

原文:https://stackoverflow.com/questions/35561782
更新时间:2019-06-23 01:10

最满意答案

有几件事:

  • Fortran使用引用调用,即默认情况下传递指针。 但是,通过指定VALUE ,您可以切换为按值调用。 这只适用于lenInOut ,所以正确的argtypes
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
  • 你有一个子程序,而不是一个函数。 所以你没有得到输出。 相反,您的代码填充数组outArray 。 永远不会触及Python代码中的数组output ,并将打印未定义的值。 正如@eryksun指出的那样,您可能希望显式声明这一点以避免从堆栈/返回值寄存器返回垃圾:
mylib.mySub.restype = None
  • 此外,虽然您指定了bind(c) ,但未精确指定函数的名称。 如果在bind属性中没有指定name ,则强制使用小写,参见 Fortran 2008第15.5.2条第2款(感谢@francescalus)。 要避免此问题,请提供bind(c, name='mySub')

  • 虽然您指定了IMPLICIT NONE ,但i未声明。

进一步改进:

  • 在子例程结束时不需要return

  • 由于ctypes转换器可以处理Python int值,您可以直接使用input2 = 5 (感谢@eryksun提示)

  • 所有ctypes缓冲区最初都归零,因此您可以简化inputoutput到inputoutput inputoutput = ArrayType()的初始化(感谢@eryksun提示)


然后完整的代码如下:

test.f90:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C, NAME='mySub')

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray
integer :: i 

print *, "outArray from within Fortran"
do i = 1, lenInOut
  outArray(i) = inArray(i)
  print *, outArray(i)
end do

end subroutine mySub

test.py:

from ctypes import *

mylib = CDLL('./mylib.so')
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
mylib.mySub.restype = None

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = 5
inputoutput = ArrayType()              

mylib.mySub( input1, input2, inputoutput )

print '------------------------------------------------------'  
print 'output within Python'
a = [0,1,2,3,4]
for ii in a: print inputoutput[ii]

A couple of things:

  • Fortran uses call by reference, i.e. by default pointers are passed. However, by specifying VALUE, you switch to call by value instead. This you do only for lenInOut, so the correct argtypes are
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
  • You have a subroutine here, not a function. So you do not get an output. Instead, your code fills the array outArray. The array output in your Python code is never touched and will print undefined values. As @eryksun points out, you might want to explicitly state that to avoid returning garbage from the stack / return value register:
mylib.mySub.restype = None
  • Furthermore, you although you specify bind(c), the name of the function is not exactly specified. If no name is specified in the bind attribute then lower case is mandated, cf. Fortran 2008 Clause 15.5.2 p2 (thanks @francescalus). To avoid this issue, provide bind(c, name='mySub').

  • Although you specify IMPLICIT NONE, i is not declared.

Further improvements:

  • You don't need a return at the end of the subroutine.

  • As the ctypes converter can handle Python int values, you can use input2 = 5 directly (thanks to @eryksun for the hint)

  • All ctypes buffers are initially zeroed, so you can simplify the initialization of inputoutput to inputoutput = ArrayType() (thanks to @eryksun for the hint)


The complete code then looks like:

test.f90:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C, NAME='mySub')

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray
integer :: i 

print *, "outArray from within Fortran"
do i = 1, lenInOut
  outArray(i) = inArray(i)
  print *, outArray(i)
end do

end subroutine mySub

test.py:

from ctypes import *

mylib = CDLL('./mylib.so')
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
mylib.mySub.restype = None

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = 5
inputoutput = ArrayType()              

mylib.mySub( input1, input2, inputoutput )

print '------------------------------------------------------'  
print 'output within Python'
a = [0,1,2,3,4]
for ii in a: print inputoutput[ii]
2016-03-07

相关问答

更多

python与c ++使用ctypes(python with c++ using ctypes)

你的代码有几个错误。 首先,正确的包括: #include <Python.h> 注意大写P 你可能在Windows上,但是如果没有大写字母P,Linux将无法工作。 另外,我没有在你的函数声明中看到*pSelf指针的指向,你应该删除它: PyObject *Add(PyObject *pArgs) 现在,你的主要问题是: MyDll.Add(1,2) ...不会使用元组调用MyDll.Add 。 它用两个整数参数1和2调用它。 如果你想传递一个元组,你会这样做: MyDll.Add((1, ...

Python,ctypes和mmap(Python, ctypes and mmap)

mmap对象“支持可写缓冲区接口”,因此,您可以使用from_buffer类方法(所有ctypes类都有),以mmap实例为参数,按照您的需要创建ctypes对象,即共享内存(因此也是底层文件) mmap实例已映射。 我想,具体来说,你会想要一个合适的ctypes 数组 。 An mmap object "supports the writable buffer interface", therefore you can use the from_buffer class method, whic ...

带回调的ctypes:退出时访问冲突(ctypes with callback: access violation on exit)

我对您的代码进行了一些小的更改,以实际运行(导入)并添加一个打印以查看传递的对象的地址和返回值,并创建一个等效的C DLL以确保指针正确传递并且回调有效。 蟒蛇: import ctypes import math def SimpleTestFunction_asm(X): Input_Length_Array = [] Input_Length_Array.append(len(X)*8) CA_X = (ctypes.c_double * len(X))(*X) ...

Python:SWIG vs ctypes(Python: SWIG vs ctypes)

SWIG生成(相当丑陋的)C或C ++代码。 直接使用简单的函数(可以直接翻译的东西),并且相对容易地用于更复杂的函数(例如具有输出参数的函数,需要一个额外的翻译步骤来表示Python)。为了更强大的接口,您经常需要将C位作为接口文件的一部分。 除了简单的使用之外,您将需要了解CPython以及它如何代表对象 - 不难,但需要牢记。 ctypes允许您直接访问C函数,结构和其他数据,并加载任意共享库。 您不需要为此编写任何C,但您需要了解C的工作原理。 您可以认为,SWIG的另一面:它不会生成代码 ...

在Python中包装C库:C,Cython或ctypes?(Wrapping a C library in Python: C, Cython or ctypes?)

ctypes是您最好的打赌,快速完成它,很高兴与您一起工作,当你仍在写Python! 我最近包装了一个FTDI驱动程序,使用ctypes与USB芯片进行通信,这是非常好的。 我已经完成了所有工作,在不到一个工作日工作。 (我只实现了我们需要的功能,大约15个功能)。 我们以前使用第三方模块PyUSB ,用于相同的目的。 PyUSB是一个实际的C / Python扩展模块。 但是PyUSB在阻止读/写操作时没有发布GIL,这对我们造成了问题。 所以我使用ctypes编写了我们自己的模块,它在调用本机 ...

Ctypes捕获异常(Ctypes catching exception)

首先,您不应该在C ++中使用异常规范。 这是C ++的一个可怕特性,它已被最新标准弃用。 此外,语法throw(...)根本不是有效的C ++,这行不能使用像gcc这样的标准符合编译器进行编译: double Divide(double a, double b) throw (...) 我认为你依赖的是非标准的Visual C ++“扩展”,据我所知,无论如何都是无用的,因为除非throw()没有参数,否则Visual C ++会忽略所有异常规范。 通过Python 2.7.3的ctypes文 ...

ctypes类成员访问segfaulting(ctypes class member access segfaulting)

使用以下解决了问题: def __init__(self): lib.Foo_new.restype = c_void_p # Needed self.obj = lib.Foo_new() def set(self, v): lib.Foo_setValue(c_void_p(self.obj), v) # c_void_p needed 阅读,它似乎是一个64位指针问题。 Using the following solved the problem: def __i ...

Python Ctypes Double De-reference Pointer(Python Ctypes Double De-reference Pointer)

我没有你的Format和Bool类型,所以有了一些替换,下面是一些示例DLL代码: #include <stddef.h> __declspec(dllexport) void ProcessAndsend(char *out, // IN char const *reqp, // IN size_t reqLen ...

相关文章

更多

最新问答

更多
  • Android宽度:100%修复(网站接管问题)(Android width:100% fix (website takeover issue))
  • C ++函数/方法设计的良好实践(Good practice in C++ function/method design)
  • 计算其他表中不存在的所有记录 - SQL查询(Count all records that does not exist to other table - SQL Query)
  • 为什么我要用JPA共享ID?(Why do I get shared Ids with JPA?)
  • asp.net - 如何显示来自html格式的数据行的字段(asp.net - how to display a field from data row that is in html format)
  • 我们如何使用ActiveRecord从连接表中删除行?(How can we delete rows from a join table by using ActiveRecord?)
  • ng-class搞乱了类的顺序(ng-class messing with the order of classes)
  • oracle 12g无效数字错误(oracle 12g invalid number error)
  • 更改ng-src值onclick(Change ng-src value onclick)
  • 如何在android中自动添加自定义依赖项以创建新项目?(How to add custom dependencies automatically in android for ever a new project is created?)
  • datetime函数在PHP中(datetime function in php)
  • 在javascript中获取会话数组的值(in javascript get the value of a session array)
  • 如何在UTF8中编译LaTeX?(How can I compile LaTeX in UTF8? [closed])
  • Rspec:“array.should == another_array”,但不用担心订单(Rspec: “array.should == another_array” but without concern for order)
  • Logcat错误:无法在android片段中加载视图(Logcat error: unable to load view in android fragments)
  • JavaFX的。(JavaFX. Adding items to the list in different threads is not working)
  • 从GDATA日历资源迁移到Google Calendar Resource api(Migrate from GDATA calendar resource to Google Calendar Resource api)
  • SSRS 2008 - 以零情景处理分割(SSRS 2008 - Dealing with division by zero scenarios)
  • 我如何以编程方式添加一个listView列标题的点击事件(How can I add a listView column header a click event programmatically)
  • Wxpython:无法检索有关列表控件项XXX的信息(Wxpython: Couldn't retrieve information about list control item XXX)
  • 使用Tortoise SVN在SVN存储库中移动目录(Move Directory across SVN repository using Tortoise SVN)
  • 天蓝色服务结构集群中的web api无状态服务是否在一段时间不活动后进入休眠状态?(Do web api stateless services in azure service fabric cluster go to sleep after a period of inactivity?)
  • 我可以设置intelliJ来突出显示PHP编码风格吗?(Can I set intelliJ to highlight php coding style?)
  • 用javafx创建一个Truetype字体文件(Creating a Truetype Font file with javafx)
  • Spring ftp配置错误(Spring ftp configuration is wrong)
  • 使用gsub去除多个字符(Using gsub to strip multiple characters)
  • 续订推送证书并保持当前的App Store App正常工作(Renew Push certificate and keep current App Store App working)
  • js:ES5和ES6之间关于'this'关键字用法的一个令人困惑的观点(js: one confusing point about 'this' keyword usage between ES5 and ES6)
  • window.onload vs $(document).ready()(window.onload vs $(document).ready())
  • 在Swift中,如何声明一个符合一个或多个协议的特定类型的变量?(In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?)