2011-06-23 30 views
83

Tôi đã tạo ra một tiện ích R script, util.R, mà tôi muốn sử dụng từ các kịch bản khác trong dự án của tôi. Cách thích hợp để đảm bảo rằng hàm mà tập lệnh này định nghĩa có sẵn để hoạt động trong các tập lệnh khác của tôi là gì?Làm thế nào để bao gồm (nguồn) R script trong các kịch bản khác

Tôi đang tìm một cái gì đó tương tự như chức năng require, tải gói chỉ khi gói chưa được tải. Tôi không muốn gọi source("util.R") vì điều đó sẽ tải tập lệnh mỗi khi được gọi.

Tôi biết rằng tôi sẽ nhận được một số câu trả lời yêu cầu tôi tạo gói, như trong Organizing R Source Code :) Nhưng tôi không tạo thứ gì đó sẽ được sử dụng ở nơi khác, nó chỉ là một dự án độc lập.

+31

Tôi tạo các gói cho các dự án độc lập mọi lúc. Nó không có nhiều công việc, và lợi ích là rất lớn. Tiếp tục, bạn biết bạn muốn làm điều đó ... – Andrie

Trả lời

73

Đây là một cách có thể. Sử dụng hàm exists để kiểm tra điều gì đó duy nhất trong mã util.R của bạn.

Ví dụ:

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

(Edited để bao gồm mode="function", như Gavin Simpson chỉ ra)

+4

Sử dụng 'exist()' - cần 'mode =" function "' để làm cho nó trở nên ngu ngốc bằng chứng –

+1

'exist()' có vẻ như là một lỗi ngoại trừ trả về một trong R 3.0.2. –

+0

Cách sử dụng chính xác là 'tồn tại (" foo ") và câu trả lời đã được chỉnh sửa. – Andrie

8

Nói util.R tạo hàm foo(). Bạn có thể kiểm tra xem chức năng này có sẵn trong môi trường toàn cầu và nguồn kịch bản nếu nó không phải là:

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

Đó sẽ tìm thấy bất cứ điều gì với tên foo. Nếu bạn muốn tìm một hàm, thì (như được đề cập bởi @Andrie) exists() là hữu ích nhưng cần phải được cho biết chính xác loại đối tượng cần tìm, ví dụ:

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

Đây là exists() trong hành động:

> 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 
+0

Trong trường hợp này, bạn có thể muốn sử dụng 'grepl (..., value = TRUE)' vì cụm từ tìm kiếm của bạn có lẽ không phải là regex. 1, nhân tiện. – Andrie

+0

?? 'grepl()' không có đối số 'value', nhưng tôi có lẽ nên sửa regexp trong' ls() '... –

+0

Xin lỗi, lỗi của tôi. Ý tôi là 'fixed = TRUE' – Andrie

15

Không có những điều như vậy built-in, vì R không theo dõi các cuộc gọi đến source và không có khả năng tìm ra những gì đã được nạp từ nơi (đây không phải là trường hợp khi sử dụng các gói). Tuy nhiên, bạn có thể sử dụng ý tưởng giống như trong các tệp C .h, tức là bọc toàn bộ trong:

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

#Code 

} 
+1

+1 đánh bại tôi bằng 32 giây ... – Andrie

+0

và sau đó gọi 'nguồn (" util.R ")' trong mã 'if', phải không? – rafalotufo

+1

@rafalotufo Bạn sẽ nguồn ("util.R") như thường lệ. Mã trong bài viết của mbq sẽ đi * vào * util.R. Bạn chỉ cần đặt toàn bộ nội dung của những gì trong util.R ngay bây giờ vào một tuyên bố if() khổng lồ, nếu điều đó có ý nghĩa. –

4

Bạn có thể viết một hàm mang theo một tên tập tin và một tên môi trường, kiểm tra xem tệp đã được tải vào môi trường và sử dụng sys.source để nguồn tệp nếu không.

Dưới đây là một chức năng nhanh chóng và chưa được kiểm tra (cải thiện chào đón!):

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

Đây là một chức năng tôi đã viết. Nó kết thúc tốt đẹp các chức năng base::source để lưu trữ một danh sách các tập tin có nguồn gốc trong một danh sách môi trường toàn cầu có tên sourced. Nó sẽ chỉ tái nguồn một tệp nếu bạn cung cấp đối số .force=TRUE cho lệnh gọi tới nguồn. Ký hiệu đối số của nó là nếu không giống với source() thực, do đó bạn không cần phải viết lại các tập lệnh của mình để sử dụng.

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, ...) 
    } 
} 

Khá thú vị (nhiều cuộc gọi đến message()) để bạn có thể lấy những dòng đó ra nếu bạn quan tâm. Bất kỳ lời khuyên từ người dùng R cựu chiến binh đều được đánh giá cao; Tôi khá mới với R.

Các vấn đề liên quan