找出在给定函数内调用哪些函数 [英] Finding out which functions are called within a given function

查看:105
本文介绍了找出在给定函数内调用哪些函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能存在重复:


I' d喜欢系统地分析一个给定的函数,以找出在该函数内调用了哪些其他函数。如果可能的话,递归的。



我在博客文章中通过 milktrader ,我可以为(或名称空间)做类似的事情。

  listFunctions<  -  function(
name,
...
){
name.0< - name
name< - paste(package ),,name,sep =)
if(!%name in%search()){
stop(paste(Invalid namespace:',name.0,'' ))
}
#作为参考
#出<-ls(名称)
funlist< - lsf.str(名称)
出< - 头(funlist,n =长度(funlist))
退货(出)
}

> listFunctions(stats)
[1]acfacf2ARadd.scope
[4]add1addmarginsaggregate
[7]聚合。 data.frameaggregate.defaultaggregate.ts
[10]AIC别名anova
....
[499]xtabs

然而,我想要一个函数,其中 name 将是函数的名称,返回值是在 name 中调用的函数的字符向量(或递归执行的列表)。



动机



我实际上需要某种基于字符的输出(向量或列表)。原因是我正在开发一个通用包装函数来并行化一个abitrary内部函数,在这个函数中,您不必经历一个耗时的试错过程,以便找出哪些其他函数内部功能取决于。因此,我之后的函数的输出将直接用于 snowfall :: sfExport()和/或 snowfall :: sfSouce

编辑2012-08-08

由于存在一些近距离投票,我会在明天检查答案如何与其他问题合并。

但这里是我的尝试:

pre $ listFunctions< - function(function.name,recursive = FALSE,
checked.functions = NULL){

#获取函数的代码:
function.code< - deparse(get(function.name))

#在左括号之前的部分:
left.brackets< - c(unlist(strsplit(function.code,
split =[[:space:]] * \\()))

called.functions< - unique(c(unlist(sapply(left.brackets,
函数(x){

#根据不能在函数名称中的任何内容进行分割。
#split =不是字母数字,不是'_',而不是'。'
words< - c(unlist(strsplit(x,split =[^ [:alnum:] _。) )))

last.word< - tail(words,1)
last.word.is.function< - tryCatch(is.function(get(last.word)) ,
error = function(e)return(FALSE))
return(last.word [last.word.is.function])
}))))

if(递归){

#checked.functions:我们需要跟踪我们检查过哪些函数
#以避免无限循环。
functs.to.check< - called.functions [!(called.functions%in%
checked.functions)]

called.functions< - unique(c (称为函数,
do.call(c,lapply(functs.to.check,function(x){
listFunctions(x,recursive = T,
checked.functions = c
call.functions))
}))))
}
return(called.functions)
}

结果:

 > ; listFunctions(listFunctions,recursive = FALSE)
[1]functiondeparsegetc
[5]unliststrsplituniquesapply
[9]tailtryCatchis.functionreturn
[13]ifdo.calllapplylistFunctions

> system.time(all.functions< - listFunctions(listFunctions,recursive = TRUE))
用户系统流逝的
92.31 0.08 93.49

>长度(all.functions)
[1] 518

如你所见,递归版本返回了很多功能。与此相关的问题是,它会返回在进程中调用的每个函数,这显然会随着您的进行而增加。无论如何,我希望你可以使用这个(或修改它)来满足你的需求。


Possible Duplicate:
Generating a Call Graph in R

I'd like to systematically analyze a given function to find out which other functions are called within that very function. If possible, recursively.

I came across this function in a blog post by milktrader with which I can do something similar for packages (or namespaces)

listFunctions <- function(
    name,
    ...
){ 
    name.0  <- name
    name    <- paste("package", ":", name, sep="")
    if (!name %in% search()) {
        stop(paste("Invalid namespace: '", name.0, "'"))
    }
    # KEEP AS REFERENCE       
#    out <- ls(name)
    funlist <- lsf.str(name)
    out     <- head(funlist, n=length(funlist))
    return(out)
}

> listFunctions("stats")
  [1] "acf"                  "acf2AR"               "add.scope"           
  [4] "add1"                 "addmargins"           "aggregate"           
  [7] "aggregate.data.frame" "aggregate.default"    "aggregate.ts"        
 [10] "AIC"                  "alias"                "anova"               
....
[499] "xtabs"   

Yet, I'd like a function where name would be the name of a function and the return value is a character vector (or a list, if done recursively) of functions that are called within name.

Motivation

I actually need some sort of character based output (vector or list). The reason for this is that I'm working on a generic wrapper function for parallelizing an abitrary "inner function" where you don't have to go through a time consuming trial-and-error process in order to find out which other functions the inner function depends on. So the output of the function I'm after will directly be used in snowfall::sfExport() and/or snowfall::sfSouce.

EDIT 2012-08-08

As there's been some close-votes due to duplicity, I'll check how answers can be merged with the other question tomorrow.

解决方案

There must be better ways out there, but here's my attempt:

listFunctions <- function(function.name, recursive = FALSE, 
                          checked.functions = NULL){

    # Get the function's code:
    function.code <- deparse(get(function.name))

    # break code up into sections preceding left brackets:
    left.brackets <- c(unlist(strsplit(function.code, 
                                       split="[[:space:]]*\\(")))

    called.functions <- unique(c(unlist(sapply(left.brackets, 
                                               function (x) {

        # Split up according to anything that can't be in a function name.
        # split = not alphanumeric, not '_', and not '.'
        words <- c(unlist(strsplit(x, split="[^[:alnum:]_.]")))

        last.word <- tail(words, 1)
        last.word.is.function <- tryCatch(is.function(get(last.word)),
                                      error=function(e) return(FALSE))
        return(last.word[last.word.is.function])
    }))))

    if (recursive){

        # checked.functions: We need to keep track of which functions 
        # we've checked to avoid infinite loops.
        functs.to.check <- called.functions[!(called.functions %in%
                                          checked.functions)]

        called.functions <- unique(c(called.functions,
            do.call(c, lapply(functs.to.check, function(x) {
                listFunctions(x, recursive = T,
                              checked.functions = c(checked.functions,          
                                                    called.functions))
                }))))
    }
    return(called.functions)
}

And the results:

> listFunctions("listFunctions", recursive = FALSE)
 [1] "function"      "deparse"       "get"           "c"            
 [5] "unlist"        "strsplit"      "unique"        "sapply"       
 [9] "tail"          "tryCatch"      "is.function"   "return"       
[13] "if"            "do.call"       "lapply"        "listFunctions"

> system.time(all.functions <- listFunctions("listFunctions", recursive = TRUE))
   user  system elapsed 
  92.31    0.08   93.49 

> length(all.functions)
  [1] 518

As you can see, the recursive version returns a lot of functions. The problem with this is it returns every function called in the process, which obviously adds up as you go. In any case, I hope you can use this (or modify it) to suit your needs.

这篇关于找出在给定函数内调用哪些函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆