2015-03-10 13 views
9

Có cách nào để ném cảnh báo (và thất bại ..) nếu một biến toàn cầu được sử dụng trong một hàm R? Tôi nghĩ rằng đó là tiết kiệm nhiều và ngăn chặn các hành vi không mong muốn ... ví dụ:Phạm vi R: không cho phép các biến toàn cục trong hàm

sUm <- 10 
sum <- function(x,y){ 
sum = x+y 
return(sUm) 
} 

do "lỗi đánh máy" trả lại hàm sẽ luôn trả về 10. Thay vì trả lại giá trị của sUm nó sẽ thất bại.

+2

Xem: [câu hỏi này] (http://stackoverflow.com/questions/25373447/how-to-detect-free-variable-names-in-r-functions) hoặc [câu hỏi này] (http: // stackoverflow.com/questions/21245850/making-sure-a-function-does-not-use-a-global-variable) hoặc [câu hỏi này] (http://stackoverflow.com/questions/6216968/r-force- phạm vi địa phương) để thảo luận thêm. – MrFlick

Trả lời

6

Câu trả lời khác của tôi là thêm về cách tiếp cận bạn có thể thực hiện trong chức năng của mình. Bây giờ tôi sẽ cung cấp một số thông tin chi tiết về những việc cần làm khi hàm của bạn được xác định.

Để đảm bảo rằng chức năng của bạn không sử dụng các biến toàn cầu khi không nên sử dụng, hãy sử dụng gói codetools.

library(codetools) 

sUm <- 10 
f <- function(x, y) { 
    sum = x + y 
    return(sUm) 
} 

checkUsage(f) 

này sẽ in ra thông điệp:

<anonymous> local variable ‘sum’ assigned but may not be used (:1)

Để xem nếu có các biến toàn cục được sử dụng trong chức năng của bạn, bạn có thể so sánh đầu ra của findGlobals() chức năng với các biến trong môi trường toàn cầu.

> findGlobals(f) 
[1] "{" "+" "=" "return" "sUm" 

> intersect(findGlobals(f), ls(envir=.GlobalEnv)) 
[1] "sUm" 

Điều đó nói với bạn rằng biến toàn cầu sUm được sử dụng bên trong f() khi nó có lẽ không cần phải có được.

+0

đây là một trong những tốt đẹp! một cách dễ dàng để kiểm tra xem các biến toàn cục có được sử dụng sai trong một hàm hay không. Không biết gói đó. Cảm ơn! – Jonas

+0

@ Jonas: Vui vì tôi có thể giúp. –

3

Sử dụng get là một cách:

sUm <- 10 
sum <- function(x,y){ 
    sum <- x+y 
    #with inherits = FALSE below the variable is only searched 
    #in the specified environment in the envir argument below 
    get('sUm', envir = environment(), inherits=FALSE) 
} 

Output:

> sum(1,6) 
Error in get("sUm", envir = environment(), inherits = FALSE) : 
    object 'sUm' not found 

Có quyền sum trong get chức năng sẽ vẫn chỉ nhìn vào bên trong môi trường của chức năng cho biến, có nghĩa là nếu có là hai biến, một biến bên trong hàm và một trong môi trường toàn cục có cùng tên, hàm sẽ luôn tìm kiếm biến bên trong môi trường của hàm và không bao giờ ở môi trường toàn cục:

sum <- 10 
sum2 <- function(x,y){ 
    sum <- x+y 
    get('sum', envir = environment(), inherits=FALSE) 
} 

> sum2(1,7) 
[1] 8 
3

Bạn có thể kiểm tra xem tên biến có xuất hiện trong danh sách biến toàn cục hay không. Lưu ý rằng điều này là không hoàn hảo nếu biến toàn cục trong câu hỏi có cùng tên như một đối số cho hàm của bạn.

if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv)) 
    stop("Do not use a global variable!") 

Chức năng stop() sẽ tạm dừng thực hiện chức năng và hiển thị thông báo lỗi đã cho.

5

Không có cách nào thay đổi vĩnh viễn cách các biến được giải quyết vì điều đó sẽ phá vỡ rất nhiều hàm. Hành vi bạn không thích thực sự rất hữu ích trong nhiều trường hợp.

Nếu biến không được tìm thấy trong hàm, R sẽ kiểm tra môi trường nơi hàm được xác định cho biến đó. Bạn có thể thay đổi môi trường này bằng chức năng environment(). Ví dụ:

environment(sum) <- baseenv() 
sum(4,5) 
# Error in sum(4, 5) : object 'sUm' not found 

Điều này hoạt động vì baseenv() trỏ đến môi trường "cơ sở" trống. Tuy nhiên, lưu ý rằng bạn không có quyền truy cập vào các chức năng khác với phương pháp này

myfun<-function(x,y) {x+y} 
sum <- function(x,y){sum = myfun(x+y); return(sUm)} 

environment(sum)<-baseenv() 
sum(4,5) 
# Error in sum(4, 5) : could not find function "myfun" 

bởi vì trong một ngôn ngữ chức năng như R, chức năng chỉ là các biến thông thường cũng được scoped trong môi trường, trong đó họ được định nghĩa và sẽ không có sẵn trong môi trường cơ sở.

Bạn sẽ phải thay đổi môi trường theo cách thủ công cho từng chức năng bạn viết. Một lần nữa, không có cách nào để thay đổi hành vi mặc định này vì nhiều hàm R và hàm cơ sở được định nghĩa trong các gói dựa trên hành vi này.

+0

làm thế nào về một chức năng làm chức năng mà sẽ làm điều này cho bạn? –

+1

Vâng, bạn vẫn còn có vấn đề đó là nó không dễ dàng để nói sự khác biệt giữa một "biến" và một "chức năng" trong R. Để được sử dụng, bạn có thể sẽ muốn truy cập vào tất cả các chức năng trong không gian tên. nhưng đôi khi bạn có thể viết các hàm trả về các hàm khác. Nó không rõ ràng với tôi những gì một wrapper thích hợp sẽ như thế nào. – MrFlick

2

Một cách khác (hay phong cách) là để giữ cho tất cả các biến toàn cầu trong một môi trường đặc biệt:

with(globals <- new.env(), { 
    # here define all "global variables" 
    sUm <- 10 
    mEan <- 5 
}) 

# or add a variable by using $ 
globals$another_one <- 42 

Sau đó, chức năng sẽ không thể để có được chúng:

sum <- function(x,y){ 
    sum = x+y 
    return(sUm) 
} 

sum(1,2) 
# Error in sum(1, 2) : object 'sUm' not found 

Nhưng bạn có thể luôn sử dụng chúng với globals $:

globals$sUm 
[1] 10 

Để quản lý kỷ luật, bạn có thể kiểm tra xem có v ariable (ngoại trừ chức năng) bên ngoài globals:

setdiff(ls(), union(lsf.str(), "globals"))) 
Các vấn đề liên quan