38

假设您有一个包含大量变量、函数和子例程的 Fortran 90 模块。在您的USE陈述中,您遵循哪种约定:

  1. 使用语法显式声明您正在使用哪些变量/函数/子例程, only :,例如 USE [module_name], only : variable1, variable2, ...
  2. 插入毯子USE [module_name]

一方面,该only子句使代码更加冗长。但是,它会迫使您在代码中重复自己,并且如果您的模块包含大量变量/函数/子例程,事情就会开始变得不规则。

这是一个例子:

module constants
  implicit none
  real, parameter :: PI=3.14
  real, parameter :: E=2.71828183
  integer, parameter :: answer=42
  real, parameter :: earthRadiusMeters=6.38e6
end module constants

program test
! Option #1:  blanket "use constants"
!  use constants
! Option #2:  Specify EACH variable you wish to use.
  use constants, only : PI,E,answer,earthRadiusMeters
  implicit none

  write(6,*) "Hello world.  Here are some constants:"
  write(6,*) PI, &
       E, &
       answer, &
       earthRadiusInMeters
end program test

更新 希望有人说“Fortran?只需用 C# 重新编码!” 所以我可以否决你。


更新

我喜欢Tim Whitcomb 的回答,它将 FortranUSE modulename与 Python 的from modulename import *. 之前在 Stack Overflow 上的一个话题:

  • “导入模块”或“从模块导入”</a>

    • Mark Roddy 在回答中提到:

      不要使用“从模块导入 *”。对于任何合理的大型代码集,如果您“导入 *”,您可能会将其固定到模块中,无法删除。这是因为很难确定代码中使用的哪些项目来自“模块”,这使得它向东到达您认为不再使用导入但很难确定的地步。

  • python导入的好的经验法则是什么?

    • dbr 的答案包含

      不要这样做 from x import * - 它使您的代码很难理解,因为您无法轻易看到方法的来源(from x import *; from y import *; my_func() - my_func 定义在哪里?)

因此,我倾向于达成共识,即通过以下方式明确说明我在模块中使用的所有项目

USE modulename, only : var1, var2, ...

正如Stefano Borini所说,

[如果]你有一个太大的模块,以至于你不得不只添加,这意味着你的模块太大了。拆分它。

4

7 回答 7

27

我以前只是这样做use modulename——然后,随着我的应用程序的增长,我发现越来越难以找到函数的源代码(不求助于 grep)——办公室周围的一些其他代码仍然使用一个子程序-file,它有自己的一系列问题,但它可以更轻松地使用文本编辑器来浏览代码并快速跟踪您需要的内容。

在经历了这一点之后,我已经成为一个转换为使用use...only尽可能。我也开始学习 Python,并以与from modulename import *. 模块为您提供了很多很棒的东西,但我更喜欢严格控制我的全局命名空间。

于 2009-08-06T18:51:37.590 回答
18

这是一个平衡的问题。

如果您只使用模块中的一些东西,那么添加 ONLY 是有意义的,以清楚地指定您正在使用的内容。

如果你使用模块中的很多东西,指定 ONLY 之后会跟着很多东西,所以它没有意义。你基本上是在挑选你使用的东西,但真正的事实是你依赖于整个模块。

然而,最终最好的理念是这样的:如果你担心命名空间污染,并且你有一个太大的模块以至于你不得不只添加,这意味着你的模块太大了。拆分它。

更新:Fortran?只需在 python 中重新编码;)

于 2009-08-06T18:21:20.413 回答
6

这里没有完全回答这个问题,只是提出另一个我发现在某些情况下有用的解决方案,如果出于某种原因你不想拆分你的模块并开始出现命名空间冲突。您可以使用派生类型在一个模块中存储多个命名空间。

如果变量有一些逻辑分组,您可以为每个组创建自己的派生类型,在模块中存储此类型的实例,然后您可以只导入您碰巧需要的组。

小例子:我们有很多数据,其中一些是用户输入,一些是杂项初始化的结果。

module basicdata
   implicit none
   ! First the data types...
   type input_data
      integer :: a, b
   end type input_data
   type init_data
      integer :: b, c
   end type init_data

   ! ... then declare the data
   type(input_data) :: input
   type(init_data) :: init
end module basicdata

现在,如果子例程仅使用来自 的数据init,则只需导入:

subroutine doesstuff
   use basicdata, only : init
   ...
   q = init%b
end subroutine doesstuff

这绝对不是一个普遍适用的解决方案,你会从派生类型语法中获得一些额外的冗长,然后如果你的模块不是basicdata上面的那种,它当然几乎没有帮助,而是更多的allthestuffivebeenmeaningtosortout种类。无论如何,我很幸运能以这种方式获得更容易进入大脑的代码。

于 2011-03-11T08:10:47.837 回答
4

仅对我而言,USE 的主要优点是它避免了我不需要的东西污染我的全局命名空间。

于 2009-08-06T18:16:24.760 回答
1

同意之前给出的大多数答案,use ..., only: ...是要走的路,在有意义的时候使用类型,尽可能多地应用python 思维。另一个建议是在导入的模块中使用适当的命名约定以及private/public语句。

例如,netcdf库使用nf90_<some name>,它限制了导入端的命名空间污染。

use netcdf  ! imported names are prefixed with "nf90_"

nf90_open(...)
nf90_create(...)
nf90_get_var(...)
nf90_close(...)

同样,该库的ncio包装器使用nc_<some name>( nc_read, nc_write...)。

重要的是,对于此类use: ..., only: ...相关性较低的设计,您最好通过在标题中设置适当的private/public属性来控制导入模块的命名空间,以便读者快速查看它足以评估哪个级别的“污染“他们面对。这与 基本相同use ..., only: ...,但在导入模块方面 - 因此只编写一次,而不是每次导入)。

还有一件事:就面向对象和python而言,我认为fortran并不真正鼓励类型绑定过程,部分原因是它是一个相对较新的标准(例如,与许多工具不兼容,并且不太合理,它只是不寻常的)并且因为它破坏了方便的行为,例如无过程派生类型复制(type(mytype) :: t1, t2t2 = t1)。这意味着您经常必须导入类型和所有可能的类型绑定过程,而不仅仅是类。与 python 相比,仅这一点就使得 fortran 代码更加冗长,而像前缀命名约定这样的实用解决方案可能会派上用场。

IMO,底线是:为将要阅读它的人选择您的编码风格(这包括您以后的自己),正如 python 所教导的那样。最好是在每次导入时更详细use ..., only: ...,但在某些情况下,一个简单的命名约定就可以做到(如果你有足够的纪律......)。

于 2015-12-12T11:58:37.493 回答
1

是的,请使用use module, only: .... 对于具有多个程序员的大型代码库,它使代码更容易被每个人(或只是使用grep)遵循。

请不要使用包含,而是使用较小的模块。Include 是源代码的文本插入,编译器未在与 use 模块相同的级别进行检查,请参阅:FORTRAN: Difference between INCLUDE and modulesInclude通常会使人和计算机都更难使用代码,这意味着不应使用它。前任。来自 mpi-forum:“强烈建议不要使用 mpif.h 包含文件,并且可能会在未来的 MPI 版本中被弃用。” (http://mpi-forum.org/docs/mpi-3.1/mpi31-report/node411.htm)。

于 2016-05-09T12:59:39.783 回答
0

我知道我参加聚会有点晚了,但如果你只是在一组常量而不一定是计算值之后,你可以像 C 一样创建一个包含文件:

在文件中,例如,constants.for

real, parameter :: pi = 3.14
real, parameter :: g = 6.67384e-11
...


program main
    use module1, only : func1, subroutine1, func2 
    implicit none

    include 'constants.for'
    ...
end program main

编辑删除“real(4)”,因为有些人认为这是不好的做法。

于 2014-11-20T22:15:34.827 回答