如何查找是否在另一个函数中使用了特定函数

时间:2015-12-02 11:40:40

标签: r

我希望能够找到函数.Deprecated是否在某个函数中使用,比如my.fun。举个例子:

my.fun <- function (...) {
  .Deprecated("my_fun")
  my_fun(...)
}

目前我正在使用

grepl(".Deprecated", as.character(body(getFromNamespace("my.fun", "mypackage"))))

哪个工作正常,在上面的例子中它返回

[1] FALSE  TRUE  FALSE

但是如果我在一个函数中使用单词.Deprecated作为一个简单的字符串,那么它也会被拾取。我知道mvbutils::foodweb()mvbutils::calleer.of()函数,但只有在我明确定义自己的.Deprecated函数时它们才有效。有人知道一种优雅的方法来搜索一个函数,而不是一个字符串吗?

1 个答案:

答案 0 :(得分:2)

健壮的解决方案必须检查函数体的语法,而不是进行字符串搜索。幸运的是,R使这相对容易:

variables = all.names(body(myfunction))
'.Deprecated' %in% variables

有一点需要注意,这不会测试.Deprecated是否实际引用base::.Deprecated; 任何使用该符号作为变量/函数名称将显示在上面。但是,在没有实际执行函数的情况下,找出符号所引用的函数是不可能的,所以这样做就好了,不执行所有函数并跟踪它们的函数调用。

您可以做的最好的事情是获取函数中使用的名称列表,并在定义函数的上下文中获取它们的定义。这可以看作是 okay 启发式:如果你的函数使用.Deprecated,并且该符号是在定义函数的上下文中定义的,那么这将产生正确的定义。但是,它会在以下情况下失败:

  • 误报:

    f1 = function () {
        .Deprecated = 42
    }
    
  • 假阴性:

    f2 = function () {
        x = get('.Deprecated', mode = 'function')
        x("f1")
    }
    

因此请谨慎使用。

calls_function = function (f, target, target_name = deparse(substitute(target_name))) {
    find_definition = function (candidates)
        mget(candidates, environment(target), mode = 'function')

    resolves_to_target = function (candidates)
        sapply(find_definition(candidates), identical, target)

    variables = unique(all.names(body(f)))
    candidates = grep(target_name, variables, fixed = TRUE)
    length(candidates) > 0 && any(resolves_to_target(variables[candidates]))
}

用法:

calls_function(f1, .Deprecated)

请注意,函数名称作为不带引号的参数传递;如果你想传递base::.Deprecated,你还需要提供“不合格”的名字作为第三个参数:

calls_function(f1, base::.Deprecated, '.Deprecated')