Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.9k views
in Technique[技术] by (71.8m points)

python - getting module has no attribute error after compiling with f2py

I have ran into a problem, while trying to make a bunch of Fortran code work in Python using f2py (in gfortran). My Fortran code has a whole bunch of subroutines and it compiles fine both in gfortran and an online virtual fortran IDE. The subroutine I'm having issues with is a mergesort subroutine (which I took from rosettastone and modified), it looks like this:

subroutine MSort(N, A, A_out)
    implicit none
    integer, intent(in) :: N 
    real, dimension(N), intent(in) :: A
    real, dimension(N), intent(out) :: A_out
    real :: work((size(A) + 1) / 2)
    A_out=A
    call MergeSort(A_out, work)
  contains

  subroutine merge(A, B, C)
    implicit none
    real, target, intent(in) :: A(:), B(:)
    real, target, intent(inout) :: C(:)
    integer :: i, j, k

    if (size(A) + size(B) > size(C)) then
        stop
    end if
    i = 1; j = 1
    do k = 1, size(C)
      if (i <= size(A) .and. j <= size(B)) then
        if (A(i) <= B(j)) then
          C(k) = A(i)
          i = i + 1
        else
          C(k) = B(j)
          j = j + 1
        end if
      else if (i <= size(A)) then
        C(k) = A(i)
        i = i + 1
      else if (j <= size(B)) then
        C(k) = B(j)
        j = j + 1
      end if
    end do
  end subroutine merge

  subroutine swap(x, y)
    implicit none
    real, intent(inout) :: x, y
    real :: tmp
    tmp = x; x = y; y = tmp
  end subroutine

  recursive subroutine MergeSort(A, work)
    implicit none
    real, intent(inout) :: A(:)
    real, intent(inout) :: work(:)
    integer :: half
    half = (size(A) + 1) / 2
    if (size(A) < 2) then
      continue
    else if (size(A) == 2) then
      if (A(1) > A(2)) then
        call swap(A(1), A(2))
      end if
    else
      call MergeSort(A( : half), work)
      call MergeSort(A(half + 1 :), work)
      if (A(half) > A(half + 1)) then
        work(1 : half) = A(1 : half)
        call merge(work(1 : half), A(half + 1:), A)
      endif
    end if
  end subroutine MergeSort
end subroutine MSort

I compiled it with

$ f2py -c -m fprogram fprogram.f90

and inserted import fprogram in the beginning of my python code (in a jupyter notebook), where I wanted to use it like this (I know original is a list, it's not dimensional issues):

size=len(original_list)
sorted_list=fprogram.MSort(size,original_list)

I got the error message

module 'fprogram' has no attribute 'MSort'

Meanwhile, when I used any other subroutine from fprogram in the same way it works perfectly. I already modified the fortran code to not have variables with intent(inout) because in a previous case this has solved my problem, but it didn't work this time. What I can I do to make python recognze this subroutine?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are 2 different errors.

At first, f2py creates all lowercase procedures. Thus, you need to call fprogram.msort which is exactly what the error message tries to tell you.

On the other hand, f2py figured out that the argument N is redundant in python. Which is why it created a function where N is an optional paramenter. Thus, you also need to call it in one of the following ways

sorted_list=fprogram.msort(original_list)
sorted_list=fprogram.msort(original_list, size)
sorted_list=fprogram.msort(original_list, n=size)

How did I find that out? I read the documentation by calling (in the python REPL)

import fprogram
help(fprogram)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...