【问题标题】:Find parent environment within call stack by function name通过函数名在调用堆栈中查找父环境
【发布时间】:2015-11-09 20:20:41
【问题描述】:

我正在一个看起来像的可变深度调用堆栈中工作

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

我对此或多或少没意见,但我不确定将调用对象转换为字符向量是否是个好主意。这种方法容易出错吗?更一般地,您将如何搜索特定的父环境,只知道函数的名称?

【问题讨论】:

    标签: r callstack


    【解决方案1】:

    像这样的fn

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

    【讨论】:

    • 感谢您的意见,但您对为什么您的解决方案优于我的解决方案有任何争论吗?
    • 好吧,一方面,在您的解决方案中,您硬编码了顶级函数的名称。它可以工作,但它可能对代码的可维护性不太好(如果您的顶级 fn 更改,您必须更改您的代码)。此外,它不能立即重用/转移到其他上下文(它只适用于那个特定的 fn)。我建议的函数是通用的,它会在任何调用堆栈中找到顶级环境,而不管函数的名称如何。也许你不关心这一点,但对我来说,关心我编写的代码的可维护性和可重用性总是很重要
    • 公平点,谢谢。虽然我总是可以将函数名变成一个参数(事实上,我已经这样做了):)
    【解决方案2】:

    我不确定我是否正确理解了您想要做什么,但是,使用parent.env(as.environment(-1)) 不可行吗?

    在这个例子中它似乎可以工作。

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

    我认为,也许其他可能性是使用&lt;&lt;-,它在全球环境中分配。但也许这不是你想要的。

    【讨论】:

    • 好主意,但如果我在 AssignmentFunctionTopLevelFunction 之间嵌套更多函数,它将无法工作。在我的情况下,调用堆栈可能有 3 或 5 个函数深,所以我不得不提取整个堆栈。至于全局赋值,由于会影响全局状态,所以通常不被接受,所以我尽量避免。
    • 啊,我明白了,那么如果你递归地获取父环境,直到你到达全局环境之前呢?...,这里的代码看起来很糟糕,所以我会发布另一个答案...
    猜你喜欢
    • 2012-09-11
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    相关资源
    最近更新 更多