我已经创建了一个实用程序R脚本util.R,我想从项目中的其他脚本中使用它。 确保此脚本定义的函数可以在我的其他脚本中运行的正确方法是什么?
我正在寻找类似于require
函数的东西,它只在尚未加载的情况下才加载包。我不想调用source("util.R")
,因为每次调用时都会加载脚本。
我知道我会得到一些答案告诉我创建一个包,就像Organizing R Source Code :) 但我不是在创造一些将在其他地方使用的东西,它只是一个独立的项目。
答案 0 :(得分:89)
这是一种可行的方法。使用exists
功能检查util.R
代码中的唯一内容。
例如:
if(!exists("foo", mode="function")) source("util.R")
(编辑为包括mode="function"
,正如Gavin Simpson指出的那样)
答案 1 :(得分:18)
内置没有这样的东西,因为R不跟踪对source
的调用,也无法弄清楚从哪里加载的内容(使用包时不是这种情况)。然而,您可以使用与C .h
文件中相同的想法,即将整体包装在:
if(!exists('util_R')){
util_R<-T
#Code
}
答案 2 :(得分:10)
说util.R
生成一个函数foo()
。您可以检查此功能是否在全局环境中可用,如果不是,则来源脚本:
if(identical(length(ls(pattern = "^foo$")), 0))
source("util.R")
这将找到名称为foo
的任何内容。如果你想找到一个函数,那么(如@Andrie所述)exists()
是有帮助的,但需要确切地告诉你要查找的对象类型,例如。
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
答案 3 :(得分:5)
您可以编写一个带有文件名和环境名称的函数,检查文件是否已加载到环境中,如果没有,则使用sys.source
来源文件。
这是一个快速且未经测试的功能(欢迎改进!):
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
}
}
答案 4 :(得分:5)
这是我写的一个函数。它包装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的新手。
答案 5 :(得分:0)
我使用代码所在的整个地址解决了我的问题: 之前:
if(!exists("foo", mode="function")) source("utils.r")
之后:
if(!exists("foo", mode="function")) source("C:/tests/utils.r")