120 votes

Comment inclure (source) R script dans d'autres script.

J'ai créé un script utilitaire R, util.R, que je veux utiliser à partir d'autres script dans mon projet. Quelle est la bonne façon de s'assurer que les fonctions définies par ce script sont disponibles pour fonctionner dans mes autres script ?

Je cherche quelque chose de similaire à la require qui ne charge un paquet que s'il n'a pas encore été chargé. Je ne veux pas appeler source("util.R") car cela chargera le script à chaque fois qu'il sera appelé.

Je sais que je recevrai des réponses me disant de créer un paquet, comme dans le cas suivant Organiser le code source de R :) Mais je ne crée pas quelque chose qui sera utilisé ailleurs, c'est juste un projet autonome.

102voto

Andrie Points 66979

Voici une solution possible. Utiliser le exists pour vérifier s'il y a quelque chose d'unique dans votre util.R code.

Par exemple :

if(!exists("foo", mode="function")) source("util.R")

(Modifié pour inclure mode="function" (comme l'a souligné Gavin Simpson)

18voto

mbq Points 8963

Il n'y a rien de tel d'intégré, puisque R ne suit pas les appels à source et n'est pas en mesure de déterminer ce qui a été chargé à partir d'où (ce qui n'est pas le cas lors de l'utilisation de paquets). Cependant, vous pouvez utiliser la même idée qu'en C .h c'est-à-dire qu'il s'agit d'envelopper l'ensemble dans un fichier :

if(!exists('util_R')){
 util_R<-T

 #Code

}

10voto

Gavin Simpson Points 72349

Dites util.R produit une fonction foo() . Vous pouvez vérifier si cette fonction est disponible dans l'environnement global, et trouver la source du script si ce n'est pas le cas :

if(identical(length(ls(pattern = "^foo$")), 0))
    source("util.R")

Cela permet de trouver tout ce qui porte le nom foo . Si vous voulez trouver une fonction, alors (comme mentionné par @Andrie) exists() est utile, mais il faut lui indiquer exactement le type d'objet à rechercher, par exemple

if(exists("foo", mode = "function"))
    source("util.R")

Voici exists() en action :

> exists("foo", mode = "function")
[1] FALSE
> foo <- function(x) x
> exists("foo", mode = "function")
[1] TRUE
> rm(foo)
> foo <- 1:10
> exists("foo", mode = "function")
[1] FALSE

5voto

Joshua Ulrich Points 68776

Vous pourriez écrire une fonction qui prend un nom de fichier et un nom d'environnement, vérifie si le fichier a été chargé dans l'environnement et utilise la fonction sys.source pour trouver la source du fichier si ce n'est pas le cas.

Voici une fonction rapide et non testée (les améliorations sont les bienvenues !):

include <- function(file, env) {
  # ensure file and env are provided
  if(missing(file) || missing(env))
    stop("'file' and 'env' must be provided")
  # ensure env is character
  if(!is.character(file) || !is.character(env))
    stop("'file' and 'env' must be a character")

  # see if env is attached to the search path
  if(env %in% search()) {
    ENV <- get(env)
    files <- get(".files",ENV)
    # if the file hasn't been loaded
    if(!(file %in% files)) {
      sys.source(file, ENV)                        # load the file
      assign(".files", c(file, files), envir=ENV)  # set the flag
    }
  } else {
    ENV <- attach(NULL, name=env)      # create/attach new environment
    sys.source(file, ENV)              # load the file
    assign(".files", file, envir=ENV)  # set the flag
  }
}

5voto

Omar S. Points 271

Voici une fonction que j'ai écrite. Elle enveloppe la fonction base::source pour stocker une liste de fichiers sources dans une liste d'environnement globale nommée sourced . Il ne re-sourcera un fichier que si vous fournissez un .force=TRUE à l'appel à la source. La signature de son argument est par ailleurs identique à celle de l'argument réel source() vous n'avez donc pas besoin de réécrire vos scripts pour l'utiliser.

warning("overriding source with my own function FYI")
source <- function(path, .force=FALSE, ...) {
  library(tools)
  path <- tryCatch(normalizePath(path), error=function(e) path)
  m<-md5sum(path)

  go<-TRUE
  if (!is.vector(.GlobalEnv$sourced)) {
    .GlobalEnv$sourced <- list()
  }
  if(! is.null(.GlobalEnv$sourced[[path]])) {
    if(m == .GlobalEnv$sourced[[path]]) {
      message(sprintf("Not re-sourcing %s. Override with:\n  source('%s', .force=TRUE)", path, path))
      go<-FALSE
    }
    else {
      message(sprintf('re-sourcing %s as it has changed from: %s to: %s', path, .GlobalEnv$sourced[[path]], m))
      go<-TRUE
    }
  } 
  if(.force) {
    go<-TRUE
    message("  ...forcing.")
  }
  if(go) {
    message(sprintf("sourcing %s", path))
    .GlobalEnv$sourced[path] <- m
    base::source(path, ...)
  }
}

Il est assez bavard (beaucoup d'appels à l'aide). message() ), vous pouvez donc supprimer ces lignes si vous le souhaitez. Tout conseil de la part d'utilisateurs chevronnés de R est le bienvenu ; je suis assez novice en la matière.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X