2015-02-13 2 views
3

У меня есть функция, задача которой - создать переменную в родительском объекте. Я хочу, чтобы функция создавала переменную на том уровне, на котором она была вызвана.R Программирование - создает переменную в среде, в которой она была вызвана

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 

Мне интересно, есть ли способ сделать это, не создавая переменную в области глобальной среды.

Редактировать: Есть ли способ модульной проверки того, что переменная была создана?

ответ

5

Попробуйте это :

createVariable <- function(var.name, var.value) { 
    assign(var.name,var.value,envir=parent.env(environment())) 
} 

Редактировать: Дополнительная информация here и here. С исходным решением переменная создается в глобальном env, потому что parent.env - это среда, в которой определена функция, и функция createVariable определена в глобальной среде.

Вы также можете попробовать assign(var.name,var.value,envir=as.environment(sys.frames()[[1]])), который будет создавать его в высшей тестовой функции вызывающей createVariable в вашем примере (первый один в стеке вызовов), в этом случае, однако, вам нужно будет удалить print(testVar) из testFunc, когда вы звоните testFunc2, потому что переменная создается только в среде 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 's окружающей среды, а не в testFunc-х гг. Создание новой среды, как говорят другие, может быть более безопасным.

+0

Есть ли какой-либо способ модульной проверки того, что переменная была создана с помощью testthat? – Shuo

+0

вы можете использовать 'exists (" testVar ")' – NicE

0

При создании новой среды и присвоить ей значение:

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) 
} 
2

Вы должны родительская среда, чтобы сделать это, не вызывающую среду:

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" 
2

Почему вы хотите это сделать? Использование assign может привести к затруднению поиска ошибок и других проблем.

Что может быть лучшим подходом, так это создать новую среду непосредственно перед вызовом интересующей вас функции. Затем в вашей функции назначьте эту новую среду (лучше всего, если среда будет передана функции, но также может использовать лексическое охват, чтобы получить к ней доступ).Тогда, когда функция возвращает вы будете иметь новые переменные среды:

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) 
} 
Смежные вопросы