2015-08-17 7 views
4

Я работаю в стеке вызовов переменной глубины, которая выглядит какНайти родительскую среду в стеке вызовов по имени функции

TopLevelFunction 
-> <SomeOtherFunction(s), 1 or more> 
    -> AssignmentFunction 

Теперь моя цель состоит в том, чтобы присвоить переменной, созданной в AssignmentFunction, к окружающей среде TopLevelFunction. Я знаю, что могу извлечь из стека с sys.calls, так что мой нынешний подход

# get the call stack and search for TopLevelFunction 
depth <- which(stringr::str_detect(as.character(sys.calls()), "TopLevelFunction")) 
# assign in TopLevelFunction's environment 
assign(varName, varValue, envir = sys.frame(depth)) 

Я более или менее хорошо с этим, хотя я не уверен, что это хорошая идея, чтобы преобразовать объекты вызовов к векторам символов. Является ли этот подход склонным к ошибкам? В более общем плане, как бы вы искали определенную родительскую среду, зная только имя функции?

ответ

0

Я не уверен, правильно ли я понял, что вы хотите сделать, но, не работает ли он, чтобы использовать parent.env(as.environment(-1))?

В этом примере это работает.

fn1 <- function() { 

    fn1.1 <- function(){ 
     assign("parentvar", "PARENT", 
       envir = parent.env(as.environment(-1))) 

    } 

    fn1.1() 
    print(parentvar) 
} 

fn1() 

Может быть другая возможность заключается в том, чтобы использовать <<-, который назначает в глобальной среде, я думаю. Но, возможно, это не то, что вы хотите.

+0

Хорошая идея, но это не сработает, если я буду устанавливать больше функций между 'AssignmentFunction' и' TopLevelFunction'. В моей ситуации стек вызовов может быть, скажем, 3 или 5 функциями в глубину, поэтому я вынужден извлечь весь стек. Что касается глобального присвоения, то он обычно нахмурился, так как влияет на глобальное состояние, поэтому я сделал все возможное, чтобы избежать этого. – tonytonov

+0

Ahh, я вижу, так что, если вы рекурсивно получите родительскую среду, пока не достигнете непосредственно перед глобальной средой? .., ... здесь код выглядит ужасно, поэтому я отправлю еще один ответ ... – elikesprogramming

1

сноска как этот

get_toplevel_env <- function(env) { 

    if (identical(parent.env(env), globalenv())) { 
     env 
    } else { 
     get_toplevel_env(parent.env(env)) 
    } 
} 

и использовать его в любом уровне ваших вложенных функций, как это?

get_toplevel_env(as.environment(-1)) 
+0

Я ценю ваш вход, но есть ли у вас какие-либо аргументы в отношении того, почему ваше решение предпочтительнее моего? – tonytonov

+0

Ну, во-первых, в вашем решении вы жестко закодировали имя функции верхнего уровня. Он работает, но это может быть не очень хорошо для ремонтопригодности вашего кода (если ваш верхний уровень fn изменяется, вам нужно изменить свой код). Кроме того, он не может быть повторно использован в другом контексте (он работает только для этого конкретного fn). Функция, которую я предлагаю, является общей и найдет среду верхнего уровня в любом стеке вызовов, независимо от имени функции. Может быть, вас это не волнует, но для меня всегда важно заботиться о ремонтопригодности и повторном использовании кода, который я пишу. – elikesprogramming

+0

Справедливая точка, спасибо. Хотя я всегда мог превратить имя функции в параметр (по сути, я уже это сделал) :) – tonytonov