[r] 다른 스크립트에 (소스) R 스크립트를 포함하는 방법
프로젝트의 다른 스크립트에서 사용하려는 유틸리티 R 스크립트 util.R을 만들었습니다. 이 스크립트가 정의하는 함수를 다른 스크립트에서 작동 할 수 있도록하는 적절한 방법은 무엇입니까?
require
아직로드되지 않은 경우에만 패키지를로드하는 함수 와 유사한 것을 찾고 있습니다. 호출 source("util.R")
할 때마다 스크립트를로드하므로 호출하고 싶지 않습니다 .
R 소스 코드 구성 에서와 같이 패키지를 생성하라는 몇 가지 답변을받을 수 있다는 것을 알고 있습니다. 하지만 다른 곳에서 사용할 무언가를 만드는 것이 아니라 독립형 프로젝트 일뿐입니다.
답변
가능한 한 가지 방법이 있습니다. exists
함수를 사용 하여 util.R
코드 에서 고유 한 것을 확인하십시오 .
예를 들면 :
if(!exists("foo", mode="function")) source("util.R")
( mode="function"
Gavin Simpson이 지적한대로 를 포함하도록 편집 됨 )
답변
R은 호출을 추적하지 않고 source
어디에서로드되었는지 파악할 수 없기 때문에 내장 된 그런 것은 없습니다 (패키지를 사용할 때는 해당되지 않습니다). 그러나 C .h
파일 에서와 동일한 아이디어를 사용할 수 있습니다 . 즉, 전체를 다음으로 래핑합니다.
if(!exists('util_R')){
util_R<-T
#Code
}
답변
Say 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
답변
파일 이름과 환경 이름을 사용하는 함수를 작성하고 파일이 환경에로드되었는지 확인하고 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
}
}
답변
여기 내가 작성한 함수가 있습니다. 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을 처음 접했습니다.
답변
내 코드가있는 전체 주소를 사용하여 문제를 해결했습니다. 이전 :
if(!exists("foo", mode="function")) source("utils.r")
후:
if(!exists("foo", mode="function")) source("C:/tests/utils.r")