如何在其他脚本中包含(源)R脚本
我创build了一个实用程序R脚本util.R,我想从我的项目中使用其他脚本。 什么是确保这个脚本定义的函数可以在我的其他脚本中运行的正确方法?
我正在寻找与require
函数类似的东西,只有在尚未加载的情况下才加载包。 我不想调用source("util.R")
因为每次调用它时都会加载脚本。
我知道我会得到一些答案告诉我创build一个包,如组织R的源代码 :)但是我没有创build一些将在别处使用的东西,它只是一个独立的项目。
这是一个可能的方法。 使用exists
函数来检查你的util.R
代码中唯一的东西。
例如:
if(!exists("foo", mode="function")) source("util.R")
(如Gavin Simpson所指出的那样,编辑包括mode="function"
)
没有内置的东西,因为R不跟踪调用source
,并不能够找出什么是从哪里加载(这不是在使用包的情况下)。 然而,你可能会使用与.h
文件相同的想法,也就是将整个包装在:
if(!exists('util_R')){ util_R<-T #Code }
说util.R
产生一个函数foo()
。 你可以检查这个函数在全局环境中是否可用,如果不是这个脚本,你可以find它:
if(identical(length(ls(pattern = "^foo$")), 0)) source("util.R")
这将find任何与名称foo
。 如果你想find一个函数,那么(如@Andrie所提到的) exists()
是有帮助的,但是需要准确地知道要查找什么types的对象,例如
if(exists("foo", mode = "function")) source("util.R")
这里是exists()
在行动:
> 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
你可以编写一个函数来获取文件名和环境名,检查文件是否已经加载到环境中,如果没有,则使用sys.source
来源文件。
这里有一个快速和未经testing的function(改进欢迎!):
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 } }
这是我写的一个函数。 它封装了base::source
函数,将源文件列表存储在名为sourced
的全局环境列表中。 如果您为调用源提供.force=TRUE
参数,它将只重新生成一个文件。 它的参数签名与真正的source()
相同,所以你不需要重写你的脚本来使用它。
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, ...) } }
这非常琐碎(大量的message()
),所以你可以把这些线,如果你在乎。 任何意见从经验丰富的R用户表示赞赏; 我对R很新。