【问题标题】:How to include (source) R script in other scripts如何在其他脚本中包含(源)R 脚本
【发布时间】:2011-09-21 08:09:23
【问题描述】:

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

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

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

【问题讨论】:

  • 我一直在为独立项目创建包。工作量不大,收益却很大。继续,你知道你想这样做......

标签: r


【解决方案1】:

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

if(!exists("foo", mode="function")) source("utils.r")

之后:

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

【讨论】:

    【解决方案2】:

    这是一种可能的方法。使用exists 函数检查util.R 代码中的独特内容。

    例如:

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

    (如 Gavin Simpson 指出的,已编辑为包含 mode="function"

    【讨论】:

    • 很好地使用 exists() - 需要添加 mode = "function" 以使其万无一失
    • exists() 似乎抛出了一个错误,除了在 R 3.0.2 中返回一个错误。
    • 正确用法是 `exists("foo") 并编辑了答案。
    【解决方案3】:

    这是我写的一个函数。它包装了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 很陌生。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 在这种情况下,您可能希望使用grepl(..., value=TRUE),因为您的搜索词可能不是正则表达式。 +1,顺便说一句。
        • ?? grepl() 没有参数value,但我可能应该修复ls() 中的正则表达式...
        • 对不起,我的错误。我的意思是fixed=TRUE
        • @Andrie - 啊,好的。无论如何它都没有用。想着想着就被拖走了。 exists() 更好,但我现在看到您在此期间发布了这样的答案。
        【解决方案6】:

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

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

        【讨论】:

        • 然后在if 代码中调用source("util.R"),对吗?
        • @rafalotufo 你会像往常一样 source("util.R") 。 mbq 帖子中的代码将进入 util.R。您只需将 util.R 中的全部内容现在放入一个巨大的 if() 语句中,如果这有意义的话。
        猜你喜欢
        • 2010-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-20
        • 1970-01-01
        • 2012-03-05
        相关资源
        最近更新 更多