В соответствии с this page (в частности, как получить доступ к общим блокам Fortran от C) и некоторым Q/A page о том, как получить доступ к C struct из Python, кажется, что мы можем получить доступ к общим блокам следующим образом (хотя это может быть не очень портативным, см. ниже):
mylib.f90
subroutine fortsub()
implicit none
integer n
common /mycom/ n
print *, "fortsub> current /mycom/ n = ", n
end
компиляции:
$ gfortran -shared -fPIC -o mylib.so mylib.f90
test.py
from __future__ import print_function
import ctypes
class Mycom(ctypes.Structure):
_fields_ = [ ("n", ctypes.c_int) ]
mylib = ctypes.CDLL("./mylib.so")
mycom = Mycom.in_dll(mylib, "mycom_")
print(" python> modifying /mycom/ n to 777")
mycom.n = 777
fortsub = mylib.fortsub_
fortsub()
Тест:
$ python test.py
python> modifying /mycom/ n to 777
fortsub> current /mycom/ n = 777
Вот, пожалуйста, обратите внимание, что имя общего блока (здесь, mycom
) производится в нижнем регистре и прикреплен один подчеркивание (по предполагающей gfortran). Поскольку это соглашение является зависимым от компилятора, оно может быть более надежным и переносимым для записи новых подпрограмм Fortran для установки/получения значений в общих блоках (в частности, с помощью iso_c_binding
) и вызова этих подпрограмм из Python (как было предложено @innoSPG в первый комментарий).
Другой пример включая различные типы и массивы могут выглядеть следующим образом:
mylib.f90
subroutine initcom()
implicit none
integer n(2), w !! assumed to be compatible with c_int
real f(2) !! ... with c_float
double precision d(2) !! ... with c_double
common /mycom/ n, f, d, w
print *, "(fort) initializing /mycom/"
n(:) = [ 1, 2 ]
f(:) = [ 3.0, 4.0 ]
d(:) = [ 5.0d0, 6.0d0 ]
w = 7
call printcom()
end
subroutine printcom()
implicit none
integer n(2), w
real f(2)
double precision d(2)
common /mycom/ n, f, d, w
print *, "(fort) current /mycom/"
print *, " n = ", n
print *, " f = ", f
print *, " d = ", d
print *, " w = ", w
end
test.py
from __future__ import print_function
import ctypes
N = 2
class Mycom(ctypes.Structure):
_fields_ = [ ("x", ctypes.c_int * N),
("y", ctypes.c_float * N),
("z", ctypes.c_double * N),
("w", ctypes.c_int ) ]
mylib = ctypes.CDLL("./mylib.so")
mycom = Mycom.in_dll(mylib, "mycom_")
initcom = mylib.initcom_
initcom()
print(" (python) current /mycom/")
print(" x = ", mycom.x[:])
print(" y = ", mycom.y[:])
print(" z = ", mycom.z[:])
print(" w = ", mycom.w )
print(" (python) modifying /mycom/ ...")
for i in range(N):
mycom.x[ i ] = (i + 1) * 10
mycom.y[ i ] = (i + 1) * 100
mycom.z[ i ] = (i + 1) * 0.1
mycom.w = 777
printcom = mylib.printcom_
printcom()
Тест:
$ python test.py
(fort) initializing /mycom/
(fort) current /mycom/
n = 1 2
f = 3.0000000 4.0000000
d = 5.0000000000000000 6.0000000000000000
w = 7
(python) current /mycom/
x = [1, 2]
y = [3.0, 4.0]
z = [5.0, 6.0]
w = 7
(python) modifying /mycom/ ...
(fort) current /mycom/
n = 10 20
f = 100.00000 200.00000
d = 0.10000000000000001 0.20000000000000001
w = 777
Почему бы вам не написать функции fortran, которые python может вызвать для доступа к этой переменной. – innoSPG
Поскольку библиотеки были разработаны давно, и я хочу избежать попытки перевести проверенную инфраструктуру. Доступ к переменным в общих блоках позволит мне использовать их в Python (часть, которая нуждается в обновлении) и оставить сотни функций на Fortran, которые не нуждаются в обновлении. – Jfreixa
Написание обертки не означает ничего обновить! Вы просто напишете Fortran setter и getter, совершенно новые процедуры. Ничего не изменишь! Ваши сотни функций могут оставаться нетронутыми. –