首页 文章

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

提问于
浏览
94

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

我正在寻找类似于 require 函数的东西,它只在尚未加载的情况下加载包 . 我不想调用 source("util.R") 因为它会在每次调用时加载脚本 .

我知道我会得到一些答案,告诉我要创建一个包,如Organizing R Source Code :)但我不会创建一些将在其他地方使用的东西,它只是一个独立的项目 .

5 回答

  • 5

    这是一种可能的方式 . 使用 exists 函数检查 util.R 代码中的唯一内容 .

    例如:

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

    (编辑包括 mode="function" ,正如Gavin Simpson指出的那样)

  • 5

    内置没有这样的东西,因为R不跟踪 source 的调用,也无法弄清楚从哪里加载的内容(使用包时不是这种情况) . 然而,您可以使用与C .h 文件中相同的想法,即将整体包装在:

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

    假设 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
    
  • 80

    您可以编写一个带有文件名和环境名称的函数,检查文件是否已加载到环境中,如果没有则使用 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
      }
    }
    
  • 10

    这是我写的一个函数 . 它包装 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的新手

相关问题