本文介绍了找出在给定函数内调用哪些函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
I' d喜欢系统地分析一个给定的函数,以找出在该函数内调用了哪些其他函数。如果可能的话,递归的。
我在博客文章中通过,我可以为包(或名称空间)做类似的事情。
listFunctions< - function(
name,
...
){
name.0< - name
name< - paste(package ),,name,sep =)
if(!%name in%search()){
stop(paste(Invalid namespace:',name.0,'' ))
}
#作为参考
#出 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
如你所见,递归版本返回了很多功能。与此相关的问题是,它会返回在进程中调用的每个函数,这显然会随着您的进行而增加。无论如何,我希望你可以使用这个(或修改它)来满足你的需求。
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.
这篇关于找出在给定函数内调用哪些函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!