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

时间:2021-10-30 08:51:40

I've created a utility R script, util.R, which I want to use from other scripts in my project. What is the proper way to ensure that the function this script defines are available to function in my other scripts?

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

I'm looking for something similar to the require function, that loads a package only if it has not been loaded yet. I don't want to call source("util.R") because that will load the script every time it is called.

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

I know that I will get some answers telling me to create a package, as in Organizing R Source Code :) But I'm not creating something that will be used elsewhere, it is just a standalone project.

我知道我会得到一些答案告诉我去创建一个包,就像在组织R源代码:)但是我不是在创建一个可以在其他地方使用的东西,它只是一个独立的项目。

5 个解决方案

#1


77  

Here is one possible way. Use the exists function to check for something unique in your util.R code.

这里有一个可能的方法。使用exist函数检查util中的某些惟一的东西。R代码。

For example:

例如:

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

(Edited to include mode="function", as Gavin Simpson pointed out)

(如加文·辛普森所指出的,包括mode="function")

#2


15  

There is no such thing built-in, since R does not track calls to source and is not able to figure out what was loaded from where (this is not the case when using packages). Yet, you may use same idea as in C .h files, i.e. wrap the whole in:

不存在这种内置的东西,因为R不跟踪对源的调用,并且无法找出从何处加载的内容(使用包时不是这样)。但是,您可以使用与C .h文件相同的思想,即将整个文件封装在:

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

 #Code

}

#3


8  

Say util.R produces a function foo(). You can check if this function is available in the global environment and source the script if it isn't:

说跑龙套。R生成一个函数foo()。您可以检查该函数在全局环境中是否可用,如果不可用,请提供脚本源代码:

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

That will find anything with the name foo. If you want to find a function, then (as mentioned by @Andrie) exists() is helpful but needs to be told exactly what type of object to look for, e.g.

它会找到任何名称为foo的东西。如果您想要找到一个函数,那么(如@Andrie所提到的)exist()是有用的,但是需要确切地告诉您要查找的对象类型,例如。

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

Here is exists() in 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

#4


4  

You could write a function that takes a filename and an environment name, checks to see if the file has been loaded into the environment and uses sys.source to source the file if not.

您可以编写一个函数,该函数接受文件名和环境名,检查文件是否已加载到环境中并使用sys。源文件,如果不是的话。

Here's a quick and untested function (improvements welcome!):

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

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

#5


4  

Here is a function I wrote. It wraps the base::source function to store a list of sourced files in a global environment list named sourced. It will only re-source a file if you provide a .force=TRUE argument to the call to source. Its argument signature is otherwise identical to the real source() so you don't need to rewrite your scripts to use this.

这是我写的函数。它封装了base::source函数,用于在名为sources的全局环境列表中存储源文件的列表。只有当您为对源的调用提供.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, ...)
  }
}

It's pretty chatty (lots of calls to message()) so you can take those lines out if you care. Any advice from veteran R users is appreciated; I'm pretty new to R.

它非常健谈(对message()有很多调用),所以如果您关心的话,可以把这些行去掉。感谢R用户的建议;我对R很陌生。

#1


77  

Here is one possible way. Use the exists function to check for something unique in your util.R code.

这里有一个可能的方法。使用exist函数检查util中的某些惟一的东西。R代码。

For example:

例如:

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

(Edited to include mode="function", as Gavin Simpson pointed out)

(如加文·辛普森所指出的,包括mode="function")

#2


15  

There is no such thing built-in, since R does not track calls to source and is not able to figure out what was loaded from where (this is not the case when using packages). Yet, you may use same idea as in C .h files, i.e. wrap the whole in:

不存在这种内置的东西,因为R不跟踪对源的调用,并且无法找出从何处加载的内容(使用包时不是这样)。但是,您可以使用与C .h文件相同的思想,即将整个文件封装在:

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

 #Code

}

#3


8  

Say util.R produces a function foo(). You can check if this function is available in the global environment and source the script if it isn't:

说跑龙套。R生成一个函数foo()。您可以检查该函数在全局环境中是否可用,如果不可用,请提供脚本源代码:

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

That will find anything with the name foo. If you want to find a function, then (as mentioned by @Andrie) exists() is helpful but needs to be told exactly what type of object to look for, e.g.

它会找到任何名称为foo的东西。如果您想要找到一个函数,那么(如@Andrie所提到的)exist()是有用的,但是需要确切地告诉您要查找的对象类型,例如。

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

Here is exists() in 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

#4


4  

You could write a function that takes a filename and an environment name, checks to see if the file has been loaded into the environment and uses sys.source to source the file if not.

您可以编写一个函数,该函数接受文件名和环境名,检查文件是否已加载到环境中并使用sys。源文件,如果不是的话。

Here's a quick and untested function (improvements welcome!):

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

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

#5


4  

Here is a function I wrote. It wraps the base::source function to store a list of sourced files in a global environment list named sourced. It will only re-source a file if you provide a .force=TRUE argument to the call to source. Its argument signature is otherwise identical to the real source() so you don't need to rewrite your scripts to use this.

这是我写的函数。它封装了base::source函数,用于在名为sources的全局环境列表中存储源文件的列表。只有当您为对源的调用提供.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, ...)
  }
}

It's pretty chatty (lots of calls to message()) so you can take those lines out if you care. Any advice from veteran R users is appreciated; I'm pretty new to R.

它非常健谈(对message()有很多调用),所以如果您关心的话,可以把这些行去掉。感谢R用户的建议;我对R很陌生。