签名文件

签名文件(.PYF文件)的语法规范是从FORTRAN 90/95语言规范中借用的。几乎所有的FORTRAN 90/95标准构造都被理解,以自由格式和固定格式(召回FORTRAN 77是FORTRAN 90/95的子集)。f2py还引入了对Fortran 90/95语言规范的一些扩展,这些语言规范有助于设计Fortran到Python接口,使其更“pythonic”。

签名文件可能包含任意Fortran代码(因此Fortran代码可以被视为签名文件)。F2PY静默地忽略与创建接口无关的Fortran构造。但是,这也包括语法错误。所以,要小心不要做。

通常,签名文件的内容区分大小写。当扫描Fortran代码并写入签名文件时,f2py会自动降低除多行块或 --no-lower 使用选项。

签名文件的语法如下所示。

python模块块

签名文件可以包含一个(推荐)或多个 python module 阻碍。 python module 块描述了python/c扩展模块的内容 <modulename>module.c 这是f2py生成的。

例外:如果 <modulename> 包含子字符串 __user__ ,然后对应 python module 块描述所谓回调函数的签名(请参见 回调参数

A python module 块具有以下结构:

python module <modulename>
  [<usercode statement>]...
  [
  interface
    <usercode statement>
    <Fortran block data signatures>
    <Fortran/C routine signatures>
  end [interface]
  ]...
  [
  interface
    module <F90 modulename>
      [<F90 module data type declarations>]
      [<F90 module routine signatures>]
    end [module [<F90 modulename>]]
  end [interface]
  ]...
end [python module [<modulename>]]

括号内 [] indicate an optional part, dots ... 表示上一部分的一个或多个。所以, []... 读取前一部分的零个或多个。

Fortran/C例程签名

Fortran例程的签名具有以下结构:

[<typespec>] function | subroutine <routine name> \
              [ ( [<arguments>] ) ] [ result ( <entityname> ) ]
  [<argument/variable type declarations>]
  [<argument/variable attribute statements>]
  [<use statements>]
  [<common block statements>]
  [<other statements>]
end [ function | subroutine [<routine name>] ]

从Fortran例程签名f2py生成具有以下签名的python/c扩展函数:

def <routine name>(<required arguments>[,<optional arguments>]):
     ...
     return <return variables>

Fortran块数据的签名具有以下结构:

block data [ <block data name> ]
  [<variable type declarations>]
  [<variable attribute statements>]
  [<use statements>]
  [<common block statements>]
  [<include statements>]
end [ block data [<block data name>] ]

类型声明

的定义 <argument/variable type declaration> 部分是

<typespec> [ [<attrspec>] :: ] <entitydecl>

在哪里?

<typespec> := byte | character [<charselector>]
           | complex [<kindselector>] | real [<kindselector>]
           | double complex | double precision
           | integer [<kindselector>] | logical [<kindselector>]

<charselector> := * <charlen>
               | ( [len=] <len> [ , [kind=] <kind>] )
               | ( kind= <kind> [ , len= <len> ] )
<kindselector> := * <intlen> | ( [kind=] <kind> )

<entitydecl> := <name> [ [ * <charlen> ] [ ( <arrayspec> ) ]
                      | [ ( <arrayspec> ) ] * <charlen> ]
                     | [ / <init_expr> / | = <init_expr> ] \
                       [ , <entitydecl> ]

  • <attrspec> 是以逗号分隔的 attributes;

  • <arrayspec> 是以逗号分隔的维度边界列表;

  • <init_expr> 是一个 `C expression`_ _.

  • <intlen> 可以是负整数 integer 类型规范。在这种情况下 integer*<negintlen> 表示无符号C整数。

如果一个参数没有 <argument type declaration> ,其类型由应用程序确定 implicit 其名称的规则。

声明

属性语句:

这个 <argument/variable attribute statement><argument/variable type declaration> 没有 <typespec> . 此外,在属性语句中,不能使用其他属性 <entitydecl> 只能是名称列表。

使用语句:

的定义 <use statement> 部分是

use <modulename> [ , <rename_list> | , ONLY : <only_list> ]

在哪里?

<rename_list> := <local_name> => <use_name> [ , <rename_list> ]

当前f2py使用 use 语句仅用于链接回调模块和 external 参数(回调函数),请参见 回调参数 .

公共块语句:

的定义 <common block statement> 部分是

common / <common name> / <shortentitydecl>

在哪里?

<shortentitydecl> := <name> [ ( <arrayspec> ) ] [ , <shortentitydecl> ]

如果A python module 块包含两个或更多 common 具有相同名称的块,附加附加声明中的变量。中的变量类型 <shortentitydecl> 定义时使用 <argument type declarations> . 注意对应的 <argument type declarations> 可能包含数组规范;那么您不需要在 <shortentitydecl> .

其他声明:

这个 <other statement> 部分是指上面没有描述的任何其他Fortran语言构造。除了

  • call 的语句和函数调用 external 参数 (`more details`_ “?”;

  • include 声明
    include '<filename>'
    include "<filename>"
    

    如果一个文件 <filename> 不存在, include 语句被忽略。否则,文件 <filename> 包含在签名文件中。 include 语句可以在签名文件的任何部分中使用,也可以在Fortran/C例程签名块之外使用。

  • implicit 声明
    implicit none
    implicit <list of implicit maps>
    

    在哪里?

    <implicit map> := <typespec> ( <list of letters or range of letters> )
    

    隐式规则用于确定变量的类型规范(从变量名称的第一个字母开始),如果未使用 <variable type declaration> . 默认隐式规则由

    implicit real (a-h,o-z,$_), integer (i-m)
    
  • entry 声明
    entry <entry name> [([<arguments>])]
    

    f2py使用例程块的签名为所有条目名生成包装器。

    提示: entry 语句可用于描述允许f2py仅从一个例程块签名生成多个包装器的任意例程的签名。执行此操作时,限制很少: fortranname 不能使用, callstatementcallprotoargument 仅当它们对所有入口例程等有效时才可使用。

此外,f2py还介绍了以下声明:

  • threadsafe

    使用 Py_BEGIN_ALLOW_THREADS .. Py_END_ALLOW_THREADS 阻止对Fortran/C函数的调用。

  • callstatement <C-expr|multi-line block>

    将f2py生成的调用语句替换为fortran/c函数 <C-expr|multi-line block> . 包装的fortran/c函数可用为 (*f2py_func) . 要引发异常,请设置 f2py_success = 0 在里面 <C-expr|multi-line block> .

  • callprotoargument <C-typespecs>

    什么时候? callstatement 使用语句,则f2py可能无法为fortran/c函数生成正确的原型(因为 <C-expr> 可能包含任何函数调用,而f2py无法确定什么应该是正确的原型)。使用此语句,可以显式指定对应原型的参数:

    extern <return type> FUNC_F(<routine name>,<ROUTINE NAME>)(<callprotoargument>);
    
  • fortranname [<actual Fortran/C routine name>]

    你可以任意使用 <routine name> 对于给定的fortran/c函数。然后你必须指定 <actual Fortran/C routine name> 用这个陈述。

    如果 fortranname 语句不使用 <actual Fortran/C routine name> 然后生成一个虚拟包装。

  • usercode <multi-line block>

    内部使用时 python module 块,然后在包装函数定义之前将给定的C代码插入到生成的C/API源中。例如,您可以在这里定义用于初始化可选参数的任意C函数。如果 usercode 里面用了两次 python module 块,然后在外部例程定义之后插入第二个多行块。

    内部使用时 <routine signature> 然后,给定的C代码将在声明变量后插入到相应的包装函数中,但插入到任何C语句之前。所以, usercode 后续操作可以同时包含声明和C语句。

    在第一次使用时 interface 块,然后给定的C代码将插入到扩展模块初始化函数的末尾。您可以在这里修改扩展模块字典。例如,用于定义附加变量等。

  • pymethoddef <multiline block>

    多行块将插入到模块方法的定义中 PyMethodDef -数组。它必须是C数组的逗号分隔列表(请参见 `Extending and Embedding`_ _有关详细信息,请参阅python文档)。 pymethoddef 语句只能在内部使用 python module 块。

属性

f2py使用以下属性:

optional

相应的参数将移动到 <optional arguments> 名单。可以指定可选参数的默认值 <init_expr>entitydecl 定义。注意,默认值必须作为有效的C表达式给出。

请注意,无论何时 <init_expr> 使用, optional 属性由f2py自动设置。

对于可选数组参数,其所有维度都必须是有界的。

required

相应的参数被认为是必需的。这是默认设置。您需要指定 required 仅当需要禁用自动 optional 设定何时 <init_expr> 使用。

如果Python None 对象用作必需参数,该参数被视为可选参数。也就是说,在array参数的情况下,会分配内存。如果 <init_expr> 给出了相应的初始化过程。

dimension(<arrayspec>)

相应变量被视为具有给定维度的数组。 <arrayspec> .

intent(<intentspec>)

这指定了相应参数的“意图”。 <intentspec> 是以下键的逗号分隔列表:

  • in

    该参数被视为仅输入的参数。这意味着参数的值被传递给fortran/c函数,该函数不应更改参数的值。

  • inout

    该参数被视为输入/输出或 就地 输出参数。 intent(inout) 参数只能是具有适当类型和大小的“连续”numpy数组。这里的“连续”可以是FORTRAN或C意义上的。后者与numpy中使用的连续概念一致,并且只有在 intent(c) 使用。默认情况下假定Fortran相邻。

    使用 intent(inout) 一般不推荐,使用 intent(in,out) 相反。也见 intent(inplace) 属性。

  • inplace

    该参数被视为输入/输出或 就地 输出参数。 intent(inplace) 参数必须是大小正确的numpy数组。如果数组的类型不是“正确”的,或者数组是非连续的,那么数组将在适当的位置进行更改,以修复类型并使其成为连续的。

    使用 intent(inplace) 通常也不推荐。例如,当从 intent(inplace) 参数,然后在就地更改之后,切片数据指针可能指向未分配的内存区域。

  • out

    该参数被视为返回变量。它被附加到 <returned variables> 名单。使用 intent(out) 集合 intent(hide) 自动,除非 intent(in)intent(inout) 使用。

    默认情况下,返回的多维数组是Fortran连续数组。如果 intent(c) 则返回的多维数组是C-连续的。

  • hide

    参数将从必需或可选参数列表中删除。典型地 intent(hide) 用于 intent(out) 或者什么时候 <init_expr> 完全确定参数的值,如下例所示:

    integer intent(hide),depend(a) :: n = len(a)
    real intent(in),dimension(n) :: a
    
  • c

    该参数被视为C标量或C数组参数。对于标量参数,它的值作为C标量参数传递给C函数(回想一下,fortran标量参数实际上是C指针参数)。对于数组参数,假设包装函数将多维数组视为C-连续数组。

    不需要使用 intent(c) 对于一维数组,无论包装函数是FORTRAN函数还是C函数。这是因为fortran-和c-邻接的概念在一维情况下重叠。

    如果 intent(c) 用作语句,但没有实体声明列表,然后f2py将 intent(c) 所有参数的属性。

    此外,在包装C函数时,必须使用 intent(c) 的属性 <routine name> 为了禁用特定于Fortran的 F_FUNC(..,..) 宏。

  • cache

    这个论点被当作记忆的垃圾。不执行Fortran或C连续性检查。使用 intent(cache) 仅对数组参数有意义,也与 intent(hide)optional 属性。

  • copy

    确保 intent(in) 参数被保留。通常用于与 intent(in,out) 属性。f2py创建可选参数 overwrite_<argument name> 使用默认值 0 .

  • overwrite

    的原始内容 intent(in) 参数可以由fortran/c函数更改。f2py创建可选参数 overwrite_<argument name> 使用默认值 1 .

  • out=<new name>

    将返回名称替换为 <new name>__doc__ 包装函数的字符串。

  • callback

    构造一个适合从Fortran调用python函数的外部函数。 intent(callback) 必须在相应的 external 语句。如果“argument”不在参数列表中,那么它将被添加到python包装器中,但只初始化外部函数。

    使用 intent(callback) 在FORTRAN/C代码假定用户使用给定的原型实现函数并将其链接到可执行文件的情况下。不要使用 intent(callback) if函数出现在Fortran例程的参数列表中。

    intent(hide)optional 指定属性并使用包装函数而不在参数列表中指定回调参数,然后在f2py生成的扩展模块的命名空间中查找回调函数,用户可以将其设置为模块属性。

  • aux

    在f2py生成的包装函数中定义辅助C变量。用于保存参数值,以便在其他变量的初始化表达式中访问这些值。注意 intent(aux) 悄悄地暗示 intent(c) .

以下规则适用:

  • 如果没有 intent(in | inout | out | hide) 已指定, intent(in) 假设。

  • intent(in,inout)intent(in) .

  • intent(in,hide)intent(inout,hide)intent(hide) .

  • intent(out)intent(out,hide) 除非 intent(in)intent(inout) 指定。

  • 如果 intent(copy)intent(overwrite) 使用,然后用一个名称引入一个附加的可选参数 overwrite_<argument name> 以及默认值0或1。

  • intent(inout,inplace)intent(inplace) .

  • intent(in,inplace)intent(inplace) .

  • intent(hide) 禁用 optionalrequired .

check([<C-booleanexpr>])

通过计算对参数执行一致性检查 <C-booleanexpr> 如果 <C-booleanexpr> 返回0,引发异常。

如果 check(..) 如果不使用,那么f2py会自动生成一些标准检查(例如,在数组参数的情况下,检查形状和大小是否正确)。使用 check() 禁用由f2py生成的检查。

depend([<names>])

这声明相应的参数取决于列表中变量的值。 <names> . 例如, <init_expr> 可以使用其他参数的值。使用提供的信息 depend(..) 属性,f2py确保参数以正确的顺序初始化。如果 depend(..) 不使用属性,则f2py自动确定依赖关系。使用 depend() 禁用由f2py生成的依赖关系。

当您编辑最初由f2py生成的依赖关系时,注意不要破坏其他相关变量的依赖关系。另一个需要注意的是循环依赖性。f2py能够在构建包装器时检测到循环依赖性,如果发现任何循环依赖性,它就会抱怨。

allocatable

对应变量是定义为Fortran 90模块数据的Fortran 90可分配数组。

external

相应的参数是用户提供的函数。可以定义此所谓回调函数的签名

  • 在里面 __user__ 模块块,

  • 或通过演示(或real,如果签名文件是真正的Fortran代码)调用 <other statements> 块。

例如,f2py生成自

external cb_sub, cb_fun
integer n
real a(n),r
call cb_sub(a,n)
r = cb_fun(4)

以下回拨签名:

subroutine cb_sub(a,n)
    real dimension(n) :: a
    integer optional,check(len(a)>=n),depend(a) :: n=len(a)
end subroutine cb_sub
function cb_fun(e_4_e) result (r)
    integer :: e_4_e
    real :: r
end function cb_fun

相应的用户提供的python函数是:

def cb_sub(a,[n]):
    ...
    return
def cb_fun(e_4_e):
    ...
    return r

也见 intent(callback) 属性。

parameter

相应的变量是一个参数,它必须有一个固定值。f2py用相应的值替换所有出现的参数。

扩展

F2PY指令

所谓的f2py指令也允许在Fortran 77/90源代码中使用f2py签名文件构造。使用此功能,您可以跳过(几乎)完全中间的签名文件生成,并将f2py直接应用于Fortran源代码。

f2py指令的格式如下:

<comment char>f2py ...

固定格式和自由格式的Fortran代码允许的注释字符为 cC*!#! ,分别。接下来的一切 <comment char>f2py 被编译器忽略,但被f2py作为普通fortran非注释行读取:

当f2py找到带有f2py指令的行时,首先用5个空格替换该指令,然后重新读取该行。

对于固定格式的Fortran代码, <comment char> 当然,必须在文件的第一列。对于自由格式的Fortran代码,f2py指令可以出现在文件的任何位置。

C表达式

C表达式用于签名文件的以下部分:

  • <init_expr> 变量初始化;

  • <C-booleanexpr>check 属性;

  • ``<arrayspec> of the `` 维度``属性;

  • callstatement 语句,这里也可以使用C多行块。

C表达式可以包含:

  • 标准C结构;

  • 功能从 math.hPython.h

  • 参数列表中的变量,可能是根据给定的依赖关系在前面初始化的;

  • 以下cpp宏:

    rank(<name>)

    返回数组的秩 <name> .

    shape(<name>,<n>)

    返回 <n> -数组的第维 <name> .

    len(<name>)

    返回数组的长度 <name> .

    size(<name>)

    返回数组的大小 <name> .

    slen(<name>)

    返回字符串的长度 <name> .

用于初始化数组 <array name> ,f2py在执行以下伪语句的所有索引和维度上生成循环:

<array name>(_i[0],_i[1],...) = <init_expr>;

在哪里? _i[<i>] 指的是 <i> -索引值和从 0shape(<array name>,<i>)-1 .

例如,函数 myrange(n) 从以下签名生成

subroutine myrange(a,n)
  fortranname        ! myrange is a dummy wrapper
  integer intent(in) :: n
  real*8 intent(c,out),dimension(n),depend(n) :: a = _i[0]
end subroutine myrange

等于 numpy.arange(n,dtype=float) .

警告

当扫描Fortran代码时,f2py也可以降低C表达式中的大小写(请参见 --[no]-lower 选择权。

多行块

多行块以开头 ''' (三个单引号)并以结尾 ''' 在一些 严格地 后续行。多行块只能在.pyf文件中使用。多行块的内容可以是任意的(除非它不能包含 ''' )并且不应用任何转换(例如降低大小写)。

当前,多行块可用于以下构造:

  • 作为 callstatement 声明;

  • 作为 callprotoargument 声明;

  • 作为C代码块 usercode 声明;

  • 作为 pymethoddef 声明;

  • 作为文档字符串。