【发布时间】:2011-09-05 12:20:24
【问题描述】:
我有一些自定义日志函数是cat 的扩展。一个基本的例子是这样的:
catt<-function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
append = FALSE)
{
cat(..., format(Sys.time(), "(%Y-%m-%d %H:%M:%S)"), "\n", file = file,
sep = sep, fill = fill, labels = labels, append = append)
}
现在,我经常使用(自制)函数,并使用其中一些日志函数来查看进度,效果很好。不过,我注意到的是,我几乎总是像这样使用这些函数:
somefunc<-function(blabla)
{
catt("somefunc: start")
#do some very useful stuff here
catt("somefunc: some time later")
#even more useful stuff
catt("somefunc: the end")
}
注意对catt 的每次调用都以调用它的函数的名称开头。在我开始重构代码和重命名函数等之前非常整洁。
感谢 Brian Ripley 的一些旧 R-list 帖子,如果我没记错的话,我找到了这段代码来获取“当前函数名”:
catw<-function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
append = FALSE)
{
curcall<-sys.call(sys.parent(n=1))
prefix<-paste(match.call(call=curcall)[[1]], ":", sep="")
cat(prefix, ..., format(Sys.time(), "(%Y-%m-%d %H:%M:%S)"), "\n",
file = file, sep = sep, fill = fill, labels = labels, append = append)
}
这很好,但并不总是有效,因为:
- 我的函数分散在
lapply中使用的匿名函数 函数类型,如下所示:
aFunc<-function(somedataframe) { result<-lapply(seq_along(somedataframe), function(i){ catw("working on col", i, "/", ncol(somedataframe)) #do some more stuff here and return something return(sum(is.na(somedataframe[[i]]))) } }
-> 对于这些情况,显然(并且可以理解)我在 catw 函数中的 sys.parent 调用中需要 n=3。
- 我偶尔使用
do.call:看来我目前的实现 也不起作用(我再一次有点理解它,不过 我还没有完全弄清楚。
所以,我的问题是:有没有办法在调用堆栈中找到第一个 named 函数(跳过日志记录函数本身,可能还有其他一些“众所周知的”异常),这将允许我要为所有情况编写一个单一版本的catw(这样我就可以愉快地重构而不用担心我的日志代码)?你会怎么处理这样的事情?
编辑:应该支持这些情况:
testa<-function(par1)
{
catw("Hello from testa, par1=", par1)
for(i in 1:2) catw("normal loop from testa, item", i)
rv<-sapply(1:2, function(i){catw("sapply from testa, item", i);return(i)})
return(rv)
}
testb<-function(par1, par2)
{
catw("Hello from testb, par1=", par1)
for(i in 1:2) catw("normal loop from testb, item", i)
rv<-sapply(1:2, function(i){catw("sapply from testb, item", i);return(i)})
catw("Will now call testa from testb")
rv2<-testa(par1)
catw("Back from testa call in testb")
catw("Will now do.call testa from testb")
rv2<-do.call(testa, list(par1))
catw("Back from testa do.call in testb")
return(list(rv, rv2))
}
testa(123)
testb(123,456)
do.call(testb, list(123,456))
【问题讨论】:
-
我经常在我的函数中使用
message()来向控制台输出一个注释,告诉我R 在函数中的哪个点。也许,message() 和 sink(...,type="message") 的某些实现对您有用?缺点是你必须把它放在你所有的函数中。 -
假设您对函数使用唯一的命名方案,是否可以将 grep 应用于 sys.call 工作?选择第一个匹配项应该是集合中最低的。
-
@Iterator:函数的命名方案现在不是一个选项。但我愿意接受相反的情况:排除某些方案(如“.*apply.*”)。
-
@尼克。我错了。我使用了一个命名方案,但是任何对您的集合(包)唯一的名称列表(好的,字符串向量)都应该足够了。获取基本 R 函数列表(或者可能是加载所有 nec. 库时的所有函数)并运行
setdiff()应该会导致这样的列表,如果您不想手动执行或无权访问命名空间。比我更熟悉 R 的人会知道如何获取此列表。