Как включить (источник) R script в другие скрипты
Я создал утилиту R script, util.R, которую я хочу использовать из других скриптов в моем проекте.
Каков правильный способ гарантировать, что функция, которую этот script определяет, доступна для работы в других моих сценариях?
Я ищу что-то похожее на функцию require
, которая загружает пакет только в том случае, если он еще не загружен. Я не хочу называть source("util.R")
, потому что он будет загружать script каждый раз, когда он вызывается.
Я знаю, что я получу несколько ответов, говорящих мне создать пакет, как в Организовать исходный код R:
Но я не создаю что-то, что будет использоваться в другом месте, это просто автономный проект.
Ответы
Ответ 1
Вот один из возможных способов. Используйте функцию exists
, чтобы проверить что-то уникальное в коде util.R
.
Например:
if(!exists("foo", mode="function")) source("util.R")
(Отредактировано для включения mode="function"
, как указал Гевин Симпсон)
Ответ 2
Нет такой встроенной вещи, так как R не отслеживает вызовы на source
и не может определить, что было загружено с этого места (это не так, когда вы используете пакеты). Тем не менее, вы можете использовать ту же идею, что и в файлах C .h
, т.е. Обернуть целое в:
if(!exists('util_R')){
util_R<-T
#Code
}
Ответ 3
Скажем util.R
выдает функцию foo()
. Вы можете проверить, доступна ли эта функция в глобальной среде и источник script, если это не так:
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
Ответ 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
Вот функция, которую я написал. Он обертывает функцию 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.