R 作用域:函数中不允许使用全局变量
R scoping: disallow global variables in function
如果在 R
函数中使用全局变量,是否有任何方法可以发出警告(并失败...)?我认为这样可以节省很多并防止意外行为......例如
sUm <- 10
sum <- function(x,y){
sum = x+y
return(sUm)
}
由于 return 中的 "typo",函数将始终 return 10
。它应该失败,而不是 returning sUm
的值。
使用get
是一种方式:
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)
}
输出:
> sum(1,6)
Error in get("sUm", envir = environment(), inherits = FALSE) :
object 'sUm' not found
在 get 函数中拥有正确的 sum
仍然只会在函数的环境中查找变量,这意味着如果有两个变量,一个在函数内部,一个在全局环境中,具有相同的变量name,该函数将始终在函数环境中查找变量,而不会在全局环境中查找:
sum <- 10
sum2 <- function(x,y){
sum <- x+y
get('sum', envir = environment(), inherits=FALSE)
}
> sum2(1,7)
[1] 8
您可以检查变量名是否出现在全局变量列表中。请注意,如果所讨论的全局变量与函数的参数同名,这是不完美的。
if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv))
stop("Do not use a global variable!")
stop()
函数将停止函数的执行并显示给定的错误消息。
无法永久更改变量的解析方式,因为这会破坏很多功能。你不喜欢的行为在很多时候其实很有用
如果在函数中找不到变量,R 将检查为此类变量定义函数的环境。您可以使用 environment()
函数更改此环境。例如
environment(sum) <- baseenv()
sum(4,5)
# Error in sum(4, 5) : object 'sUm' not found
这是有效的,因为 baseenv()
指向空的 "base" 环境。但是,请注意,您无法使用此方法访问其他功能
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"
因为在 R 等函数式语言中,函数只是常规变量,它们也在定义它们的环境中起作用,并且在基础环境中不可用。
您必须手动更改您编写的每个函数的环境。同样,无法更改此默认行为,因为包中定义的许多基本 R 函数和函数都依赖于此行为。
另一种方式(或风格)是将所有全局变量保存在一个特殊的环境中:
with( globals <- new.env(), {
# here define all "global variables"
sUm <- 10
mEan <- 5
})
# or add a variable by using $
globals$another_one <- 42
那么函数将无法获取它们:
sum <- function(x,y){
sum = x+y
return(sUm)
}
sum(1,2)
# Error in sum(1, 2) : object 'sUm' not found
但您始终可以将它们与全局变量一起使用$:
globals$sUm
[1] 10
要管理纪律,可以检查globals
之外是否有任何全局变量(函数除外):
setdiff(ls(), union(lsf.str(), "globals")))
我的另一个答案更多是关于您可以在函数内部采用什么方法。现在,我将提供一些关于定义函数后要做什么的见解。
为确保您的函数在不该使用的情况下不使用全局变量,请使用 codetools
程序包。
library(codetools)
sUm <- 10
f <- function(x, y) {
sum = x + y
return(sUm)
}
checkUsage(f)
这将打印消息:
<anonymous> local variable ‘sum’ assigned but may not be used (:1)
要查看您的函数中是否使用了任何全局变量,您可以将 findGlobals()
函数的输出与全局环境中的变量进行比较。
> findGlobals(f)
[1] "{" "+" "=" "return" "sUm"
> intersect(findGlobals(f), ls(envir=.GlobalEnv))
[1] "sUm"
这告诉您全局变量 sUm
在 f()
中被使用,而它可能不应该被使用。
如果在 R
函数中使用全局变量,是否有任何方法可以发出警告(并失败...)?我认为这样可以节省很多并防止意外行为......例如
sUm <- 10
sum <- function(x,y){
sum = x+y
return(sUm)
}
由于 return 中的 "typo",函数将始终 return 10
。它应该失败,而不是 returning sUm
的值。
使用get
是一种方式:
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)
}
输出:
> sum(1,6)
Error in get("sUm", envir = environment(), inherits = FALSE) :
object 'sUm' not found
在 get 函数中拥有正确的 sum
仍然只会在函数的环境中查找变量,这意味着如果有两个变量,一个在函数内部,一个在全局环境中,具有相同的变量name,该函数将始终在函数环境中查找变量,而不会在全局环境中查找:
sum <- 10
sum2 <- function(x,y){
sum <- x+y
get('sum', envir = environment(), inherits=FALSE)
}
> sum2(1,7)
[1] 8
您可以检查变量名是否出现在全局变量列表中。请注意,如果所讨论的全局变量与函数的参数同名,这是不完美的。
if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv))
stop("Do not use a global variable!")
stop()
函数将停止函数的执行并显示给定的错误消息。
无法永久更改变量的解析方式,因为这会破坏很多功能。你不喜欢的行为在很多时候其实很有用
如果在函数中找不到变量,R 将检查为此类变量定义函数的环境。您可以使用 environment()
函数更改此环境。例如
environment(sum) <- baseenv()
sum(4,5)
# Error in sum(4, 5) : object 'sUm' not found
这是有效的,因为 baseenv()
指向空的 "base" 环境。但是,请注意,您无法使用此方法访问其他功能
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"
因为在 R 等函数式语言中,函数只是常规变量,它们也在定义它们的环境中起作用,并且在基础环境中不可用。
您必须手动更改您编写的每个函数的环境。同样,无法更改此默认行为,因为包中定义的许多基本 R 函数和函数都依赖于此行为。
另一种方式(或风格)是将所有全局变量保存在一个特殊的环境中:
with( globals <- new.env(), {
# here define all "global variables"
sUm <- 10
mEan <- 5
})
# or add a variable by using $
globals$another_one <- 42
那么函数将无法获取它们:
sum <- function(x,y){
sum = x+y
return(sUm)
}
sum(1,2)
# Error in sum(1, 2) : object 'sUm' not found
但您始终可以将它们与全局变量一起使用$:
globals$sUm
[1] 10
要管理纪律,可以检查globals
之外是否有任何全局变量(函数除外):
setdiff(ls(), union(lsf.str(), "globals")))
我的另一个答案更多是关于您可以在函数内部采用什么方法。现在,我将提供一些关于定义函数后要做什么的见解。
为确保您的函数在不该使用的情况下不使用全局变量,请使用 codetools
程序包。
library(codetools)
sUm <- 10
f <- function(x, y) {
sum = x + y
return(sUm)
}
checkUsage(f)
这将打印消息:
<anonymous> local variable ‘sum’ assigned but may not be used (:1)
要查看您的函数中是否使用了任何全局变量,您可以将 findGlobals()
函数的输出与全局环境中的变量进行比较。
> findGlobals(f)
[1] "{" "+" "=" "return" "sUm"
> intersect(findGlobals(f), ls(envir=.GlobalEnv))
[1] "sUm"
这告诉您全局变量 sUm
在 f()
中被使用,而它可能不应该被使用。