r

Cómo incluir script(fuente) R en otros scripts



(5)

Aquí hay una función que escribí. Contiene la función base::source para almacenar una lista de archivos de origen en una lista de entorno global denominada sourced . Solo volverá a .force=TRUE un archivo si proporciona un argumento .force=TRUE para la llamada a la fuente. Su firma de argumento es idéntica a la source() real source() por lo que no necesita volver a escribir sus scripts para usar esto.

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, ...) } }

Es bastante hablador (muchas llamadas al message() ) para que pueda sacar esas líneas si le importa. Cualquier consejo de veteranos usuarios de R es apreciado; Soy bastante nuevo para R.

Creé un script R de utilidad, util.R, que quiero usar de otros scripts en mi proyecto. ¿Cuál es la forma correcta de garantizar que la función que define este script esté disponible para funcionar en mis otros scripts?

Estoy buscando algo similar a la función require , que carga un paquete solo si aún no se ha cargado. No deseo llamar a source("util.R") porque eso cargará el script cada vez que se llame.

Sé que obtendré algunas respuestas diciéndome que cree un paquete, como en Organizing R Source Code :) Pero no crearé algo que vaya a usarse en otro lado, es solo un proyecto independiente.


Aquí hay una manera posible. Use la función exists para buscar algo único en su código util.R

Por ejemplo:

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

(Editado para incluir mode="function" , como señaló Gavin Simpson)


Diga util.R produce una función foo() . Puede verificar si esta función está disponible en el entorno global y generar el script si no lo está:

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

Eso encontrará algo con el nombre foo . Si desea encontrar una función, entonces (como lo menciona @Andrie) exists() es útil, pero necesita que se le diga exactamente qué tipo de objeto buscar, por ej.

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

Aquí está exists() en acción:

> 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


No existe tal cosa incorporada, ya que R no rastrea las llamadas a la source y no es capaz de determinar qué se cargó desde allí (este no es el caso cuando se usan paquetes). Sin embargo, puede usar la misma idea que en los archivos C .h , es decir, envolver el conjunto en:

if(!exists(''util_R'')){ util_R<-T #Code }


Puede escribir una función que tome un nombre de archivo y un nombre de entorno, compruebe si el archivo se ha cargado en el entorno y utiliza sys.source para obtener el archivo si no lo está.

Aquí hay una función rápida y no probada (¡mejoras bienvenidas!):

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 } }