如何在其他脚本中包含(源)R脚本

如何在其他脚本中包含(源)R脚本,r,R,我已经创建了一个实用程序R脚本util.R,我想从项目中的其他脚本使用它。 确保此脚本定义的函数在我的其他脚本中可用的正确方法是什么 我正在寻找类似于require函数的东西,该函数仅在尚未加载包时才加载包。我不想调用source(“util.R”),因为每次调用脚本时都会加载脚本 我知道我会得到一些答案,告诉我创建一个包,如:) 但是我并没有创建将在其他地方使用的东西,它只是一个独立的项目。比如说util.R生成一个函数foo()。您可以检查此函数在全局环境中是否可用,如果不可用,则为脚本提供

我已经创建了一个实用程序R脚本util.R,我想从项目中的其他脚本使用它。 确保此脚本定义的函数在我的其他脚本中可用的正确方法是什么

我正在寻找类似于
require
函数的东西,该函数仅在尚未加载包时才加载包。我不想调用
source(“util.R”)
,因为每次调用脚本时都会加载脚本

我知道我会得到一些答案,告诉我创建一个包,如:)
但是我并没有创建将在其他地方使用的东西,它只是一个独立的项目。

比如说
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
>存在(“foo”,mode=“function”)
[1] 假的
>foo存在(“foo”,mode=“function”)
[1] 真的
>rm(foo)
>foo存在(“foo”,mode=“function”)
[1] 假的

没有内置的功能,因为R不跟踪对
源代码的调用,也无法找出从何处加载的内容(使用包时不是这种情况)。但是,您可以使用与C
.h
文件相同的想法,即将整个文件包装在:

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

 #Code

}
如果(!存在('util_R')){

util\u R这里有一种可能的方法。使用
exists
函数检查
util.R
代码中是否存在唯一的内容

例如:

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

(如Gavin Simpson所指出的,编辑为包含
mode=“function”

您可以编写一个函数,该函数采用文件名和环境名称,检查文件是否已加载到环境中,如果未加载,则使用
sys.source
来获取文件的源代码

这里有一个快速且未经测试的函数(欢迎改进!):


include这是我编写的一个函数。它包装了
base::source
函数,将源文件列表存储在名为
sourceed
的全局环境列表中。只有在调用源代码时提供
.force=TRUE
参数,它才会重新生成文件。它的参数签名与真正的相同e> 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, ...)
  }
}
警告(“用我自己的函数覆盖源代码仅供参考”)

source我使用我的代码所在的整个地址解决了我的问题: 之前:

之后:

if(!exists("foo", mode="function")) source("C:/tests/utils.r")

我一直在为独立项目创建包。这不需要做很多工作,而且好处巨大。继续,你知道你想这么做……在这种情况下,你可能需要使用
grepl(…,value=TRUE)
,因为你的搜索词可能不是正则表达式。+1,顺便说一下。??
grepl()
没有参数
,但我可能应该在
ls()
中修复regexp…对不起,我的错误。我的意思是
fixed=TRUE
@Andrie-啊,好吧。反正它不起作用。在考虑这个问题时被拖走了。
存在()
更好,但我现在看到你同时发布了这样一个答案。很好地使用了
exists()
-需要
mode=“function”
添加以使其成为傻瓜
exists()
除了在R3.0.2中返回一个之外,似乎抛出了一个错误。正确的用法是`exists(“foo”),并且答案已编辑。然后调用
source(“util.R”)
if
代码中,对吗?@rafalotufo你会像往常一样源代码(“util.R”)。mbq帖子中的代码会进入util.R。如果有意义的话,你只需将util.R中的全部内容放入一个巨大的if()语句中。
if(!exists("foo", mode="function")) source("utils.r")
if(!exists("foo", mode="function")) source("C:/tests/utils.r")