Come si utilizzano i dati del modulo Fortran 90

Supponiamo che tu abbia un modulo Fortran 90 contenente un sacco di variabili, funzioni e subroutine. Nella tua dichiarazione USE , quale convenzione segui:

  1. dichiarare esplicitamente quali variabili / funzioni / subroutine utilizzate con la syntax , only : , USE [module_name], only : variable1, variable2, ... ?
  2. Inserisci una coperta USE [module_name] ?

Da un lato, l’ only clausola rende il codice un po ‘più prolisso. Tuttavia, ti costringe a ripeterti nel codice e se il tuo modulo contiene molte variabili / funzioni / subroutine, le cose cominciano a sembrare indisciplinate.

Ecco un esempio:

 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 

Aggiornamento Speriamo che qualcuno dica qualcosa come “Fortran? Ricodificalo in C #!” quindi posso votare per te.


Aggiornare

Mi piace la risposta di Tim Whitcomb , che confronta il USE modulename con Python’s from modulename import * . Un argomento che è stato su Stack Overflow prima:

  • ‘import module’ o ‘from module import’

    • In una risposta , Mark Roddy ha menzionato:

      non usare ‘from module import *’. Per qualsiasi ragionevole insieme di codice, se si “importa”, è probabile che lo si possa cementare nel modulo, senza poter essere rimosso. Questo perché è difficile determinare quali elementi utilizzati nel codice provengano dal “modulo”, facendolo est per arrivare al punto in cui si pensa di non usare più l’importazione ma è estremamente difficile essere sicuri.

  • Quali sono le regole pratiche per importare Python?

    • la risposta di dbr contiene

      non fare da x import * – rende il tuo codice molto difficile da capire, dato che non puoi facilmente vedere da dove proviene un metodo (da x import *; da y import *; my_func () – dove è definito my_func?)

Quindi, mi sto appoggiando ad un consenso di dichiarare esplicitamente tutti gli elementi che sto usando in un modulo tramite

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

E come ricorda Stefano Borini ,

[Se] hai un modulo così grande che ti senti costretto ad aggiungere SOLO, significa che il tuo modulo è troppo grande. Dividilo.

È una questione di equilibrio.

Se si utilizzano solo poche cose dal modulo, ha senso se si aggiunge SOLO, per specificare chiaramente cosa si sta utilizzando.

Se usi un sacco di cose dal modulo, specificando SOLO sarà seguito da un sacco di cose, quindi ha meno senso. Fondamentalmente stai selezionando la tua creatività, ma il vero fatto è che tu sei dipendente da quel modulo nel suo complesso.

Tuttavia, alla fine la migliore filosofia è questa: se sei preoccupato per l’inquinamento da spazio dei nomi, e hai un modulo così grande che ti senti costretto ad aggiungere SOLO, significa che il tuo modulo è troppo grande. Dividilo.

Aggiornamento: Fortran? basta ricodificarlo in python;)

use modulename solo use modulename – poi, con l’aumentare della mia applicazione, trovavo sempre più difficile trovare l’origine delle funzioni (senza passare a grep) – alcuni degli altri codici che girano attorno all’ufficio usano ancora una subroutine -per-file, che ha il suo set di problemi, ma rende molto più facile usare un editor di testo per spostarsi nel codice e rintracciare rapidamente ciò di cui hai bisogno.

Dopo averlo sperimentato, sono diventato un convertito use usando … only quando ansible. Ho anche iniziato a raccogliere Python e visualizzarlo allo stesso modo from modulename import * . Ci sono un sacco di grandi cose che i moduli ti danno, ma preferisco mantenere il mio spazio dei nomi globale strettamente controllato.

Non rispondendo esattamente alla domanda qui, semplicemente lanciando un’altra soluzione che ho trovato utile in alcune circostanze, se per qualche ragione non si desidera dividere il modulo e iniziare a ottenere scontri nello spazio dei nomi. È ansible utilizzare i tipi derivati ​​per memorizzare diversi spazi dei nomi in un modulo.

Se esiste un raggruppamento logico delle variabili, è ansible creare il proprio tipo derivato per ciascun gruppo, memorizzare un’istanza di questo tipo nel modulo e quindi è ansible importare solo il gruppo di cui si ha bisogno.

Piccolo esempio: abbiamo molti dati alcuni dei quali sono input dell’utente e alcuni sono il risultato di varie inizializzazioni.

 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 

Ora se una subroutine utilizza solo dati da init , si importa solo questo:

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

Questa non è sicuramente una soluzione universalmente applicabile, si ottiene un po ‘di verbosità in più dalla syntax del tipo derivato e quindi sarà di certo a malapena utile se il modulo non è l’ordinamento di base di dati sopra, ma piuttosto più di una varietà molto interessante. Ad ogni modo, ho avuto un po ‘di fortuna nell’ottenere codice che si adatti più facilmente al cervello in questo modo.

Il vantaggio principale di USE, SOLO per me, è che evita di inquinare il mio spazio dei nomi globale con cose che non mi servono.

D’accordo con la maggior parte delle risposte fornite in precedenza, use ..., only: ... è la strada da percorrere, usa i tipi quando ha senso, applica il più ansible il pensiero di Python . Un altro suggerimento è di utilizzare convenzioni di denominazione appropriate nel modulo importato, insieme a dichiarazioni private / public .

Ad esempio, la libreria netcdf utilizza nf90_ , che limita l’inquinamento dello spazio dei nomi sul lato dell’importatore.

 use netcdf ! imported names are prefixed with "nf90_" nf90_open(...) nf90_create(...) nf90_get_var(...) nf90_close(...) 

allo stesso modo, il wrapper ncio di questa libreria usa nc_ ( nc_read , nc_write …).

È importante sottolineare che con tali disegni in cui use: ..., only: ... è reso meno rilevante, è meglio controllare lo spazio dei nomi del modulo importato impostando appropriati attributi private / public nell’intestazione, in modo da dare una rapida occhiata a sarà sufficiente che i lettori valutino il livello di “inquinamento” che stanno affrontando. Questo è fondamentalmente lo stesso di use ..., only: ... , ma sul lato del modulo importato – quindi deve essere scritto una sola volta, non ad ogni importazione).

Ancora una cosa: per quanto riguarda l’orientamento agli oggetti e Python, una differenza nella mia opinione è che Fortran non incoraggia realmente le procedure legate al tipo, in parte perché è uno standard relativamente nuovo (ad esempio non compatibile con un numero di strumenti e meno razionalmente, è solo inusuale) e perché rompe un comportamento a portata di mano come copia di tipo derivato senza procedure ( type(mytype) :: t1, t2 e t2 = t1 ). Ciò significa che spesso devi importare il tipo e tutte le procedure vincolate al tipo, invece della sola class. Questo da solo rende il codice di Fortran più dettagliato rispetto a Python, e soluzioni pratiche come una convenzione di denominazione dei prefissi possono tornare utili.

IMO, la linea di fondo è: scegli il tuo stile di codice per le persone che lo leggeranno (questo include il tuo sé successivo), come insegnato da python. Il migliore è l’ use ..., only: ... più prolisso use ..., only: ... ad ogni importazione, ma in alcuni casi una semplice convenzione di denominazione lo farà (se sei abbastanza disciplinato …).

Sì, per favore usa il use module, only: ... Per basi di codice di grandi dimensioni con più programmatori, rende il codice più facile da seguire da parte di tutti (o semplicemente usa grep ).

Per favore non usare include, usa invece un modulo più piccolo. Includi è un inserimento di testo del codice sorgente che non viene controllato dal compilatore allo stesso livello del modulo di utilizzo, vedi: FORTRAN: Differenza tra INCLUDE e moduli . Include generalmente rende più difficile per gli esseri umani e il computer usare il codice, il che significa che non dovrebbe essere usato. Ex. da mpi-forum: “L’uso del file include mpif.h è fortemente sconsigliato e potrebbe essere deprecato in una versione futura di MPI.” ( http://mpi-forum.org/docs/mpi-3.1/mpi31-report/node411.htm ).

So che sono un po ‘in ritardo per la festa, ma se sei solo dopo un insieme di costanti e non necessariamente valori calcolati, potresti fare come C e creare un file include:

all’interno di un file, ad esempio, 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 

Modificato per rimuovere “reale (4)” come alcuni pensano che sia una ctriggers pratica.