R Programming - 在它被调用的环境中创建变量
R Programming - creates variable in in the environment it was called
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是函数在调用它的级别创建变量。
createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=parent.frame())
}
# Works
testFunc <- function() {
createVariable("testVar","test")
print(testVar)
}
# Doesn't work
testFunc2 <- function() {
testFunc()
print(testVar)
}
> testFunc()
[1] "test"
> testFunc2()
[1] "test"
Error in print(testVar) : object 'testVar' not found
我想知道是否有任何方法可以在不在全局环境范围内创建变量的情况下执行此操作。
编辑:是否还有一种方法可以对已创建的变量进行单元测试?
如果您创建一个新环境并为其赋值:
my.env <- new.env()
my.env$my.object <- runif(1)
然后使用get
调用它:
> my.object # not found in global env
Error: object 'my.object' not found
> get("my.object", envir = my.env)
[1] 0.07912637
对于你的功能:
createVariable <- function(env.name, var.name, var.value) {
env.name <- new.env()
assign(var.name, var.value, envir = env.name)
}
试试这个:
createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=parent.env(environment()))
}
编辑:
更多细节 here and here。
有了最初的解决方案,变量是在全局环境中创建的,因为parent.env
是函数定义的环境,而createVariable
函数是在全局环境中定义的。
您可能还想尝试 assign(var.name,var.value,envir=as.environment(sys.frames()[[1]]))
,这将在您的示例中调用 createVariable
的最高测试函数中创建它(调用堆栈中的第一个),但是在这种情况下,您当您调用 testFunc2
时,需要从 testFunc
中删除 print(testVar)
,因为该变量仅在 testFunc2
的环境中创建,而不是 testFunc
。我不知道你说的 at the level at which it's called
.
是不是这个意思
如果你运行这个:
createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=as.environment(sys.frames()[[1]]))
print("creating")
}
testFunc <- function() {
createVariable("testVar","test")
print("func1")
print(exists("testVar"))
}
testFunc2 <- function() {
testFunc()
print("func2")
print(exists("testVar"))
}
testFunc()
testFunc2()
你得到
> testFunc()
[1] "creating"
[1] "func1"
[1] TRUE
> testFunc2()
[1] "creating"
[1] "func1"
[1] FALSE
[1] "func2"
[1] TRUE
这意味着 testVar
在 testFun2
的环境中,而不是在 testFunc
的环境中。像其他人说的那样创建一个新环境可能更安全。
您需要父环境来执行此操作,而不是调用环境:
createVariable <- function(var.name, var.value) {
#use parent.env(environment())
assign(var.name,var.value,envir=parent.env(environment()))
}
> testFunc()
[1] "test"
> testFunc2()
[1] "test"
[1] "test"
你为什么要这样做?使用 assign
会导致难以发现错误和其他问题。
更好的方法可能是在调用您感兴趣的函数之前创建一个新环境。然后在你的函数中分配到那个新环境(最好是将环境传递给函数,但也可以使用词法范围来访问它)。然后当函数 returns 时,您将在环境中拥有新变量:
createVariable <- function(var.name, var.value, env) {
env[[var.name]] <- var.value
}
testfunc <- function() {
tmpenv <- new.env()
createVariable('x', 1:10, tmpenv)
print(ls())
print(ls(env=tmpenv))
print(tmpenv$x)
}
如果 createVariable
是在 testfunc
内部定义的,那么它可以直接访问 tmpenv
而无需向下传递(但尽可能向下传递是最安全的)。
这个版本的 createVariable
甚至可以更直接地用于在调用函数的环境中赋值(但这变得更加危险,太容易在当前环境中覆盖某些东西,或者试图访问某些东西由于一个小错字而用了错误的名字):
testfunc2 <- function() {
createVariable('y', 5:1, environment())
print(ls())
print(y)
}
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是函数在调用它的级别创建变量。
createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=parent.frame())
}
# Works
testFunc <- function() {
createVariable("testVar","test")
print(testVar)
}
# Doesn't work
testFunc2 <- function() {
testFunc()
print(testVar)
}
> testFunc()
[1] "test"
> testFunc2()
[1] "test"
Error in print(testVar) : object 'testVar' not found
我想知道是否有任何方法可以在不在全局环境范围内创建变量的情况下执行此操作。
编辑:是否还有一种方法可以对已创建的变量进行单元测试?
如果您创建一个新环境并为其赋值:
my.env <- new.env()
my.env$my.object <- runif(1)
然后使用get
调用它:
> my.object # not found in global env
Error: object 'my.object' not found
> get("my.object", envir = my.env)
[1] 0.07912637
对于你的功能:
createVariable <- function(env.name, var.name, var.value) {
env.name <- new.env()
assign(var.name, var.value, envir = env.name)
}
试试这个:
createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=parent.env(environment()))
}
编辑:
更多细节 here and here。
有了最初的解决方案,变量是在全局环境中创建的,因为parent.env
是函数定义的环境,而createVariable
函数是在全局环境中定义的。
您可能还想尝试 assign(var.name,var.value,envir=as.environment(sys.frames()[[1]]))
,这将在您的示例中调用 createVariable
的最高测试函数中创建它(调用堆栈中的第一个),但是在这种情况下,您当您调用 testFunc2
时,需要从 testFunc
中删除 print(testVar)
,因为该变量仅在 testFunc2
的环境中创建,而不是 testFunc
。我不知道你说的 at the level at which it's called
.
如果你运行这个:
createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=as.environment(sys.frames()[[1]]))
print("creating")
}
testFunc <- function() {
createVariable("testVar","test")
print("func1")
print(exists("testVar"))
}
testFunc2 <- function() {
testFunc()
print("func2")
print(exists("testVar"))
}
testFunc()
testFunc2()
你得到
> testFunc()
[1] "creating"
[1] "func1"
[1] TRUE
> testFunc2()
[1] "creating"
[1] "func1"
[1] FALSE
[1] "func2"
[1] TRUE
这意味着 testVar
在 testFun2
的环境中,而不是在 testFunc
的环境中。像其他人说的那样创建一个新环境可能更安全。
您需要父环境来执行此操作,而不是调用环境:
createVariable <- function(var.name, var.value) {
#use parent.env(environment())
assign(var.name,var.value,envir=parent.env(environment()))
}
> testFunc()
[1] "test"
> testFunc2()
[1] "test"
[1] "test"
你为什么要这样做?使用 assign
会导致难以发现错误和其他问题。
更好的方法可能是在调用您感兴趣的函数之前创建一个新环境。然后在你的函数中分配到那个新环境(最好是将环境传递给函数,但也可以使用词法范围来访问它)。然后当函数 returns 时,您将在环境中拥有新变量:
createVariable <- function(var.name, var.value, env) {
env[[var.name]] <- var.value
}
testfunc <- function() {
tmpenv <- new.env()
createVariable('x', 1:10, tmpenv)
print(ls())
print(ls(env=tmpenv))
print(tmpenv$x)
}
如果 createVariable
是在 testfunc
内部定义的,那么它可以直接访问 tmpenv
而无需向下传递(但尽可能向下传递是最安全的)。
这个版本的 createVariable
甚至可以更直接地用于在调用函数的环境中赋值(但这变得更加危险,太容易在当前环境中覆盖某些东西,或者试图访问某些东西由于一个小错字而用了错误的名字):
testfunc2 <- function() {
createVariable('y', 5:1, environment())
print(ls())
print(y)
}