最近一位同事正在查看电话号码,并希望了解所谓的内容。我们用mvbutils的foodweb对它进行了排序,但我想知道如何最好地在R中创建一个装饰器(用python说话)。所以我这样做了:
instrument=function(z){
force(z)
n=deparse(substitute(z)) # get the name
f=function(...){
cat("calling ", n,"\n")
x=z(...)
cat("done\n")
return(x)
}
return(f)
}
这让我这样做:
> foo=function(x,y){x+y}
> foo(1,2)
[1] 3
现在我可以通过包装它来使函数自身记录:
> foo=instrument(foo)
> foo(1,2)
calling foo
done
[1] 3
之前已经完成过,在一个软件包中说过,我是否错过了任何会破坏我这样做的陷阱?
答案 0 :(得分:10)
R中的trace
函数可以做到这一点。请参阅?trace
。
答案 1 :(得分:4)
我的github软件包 tag 试图解决此问题。
您的示例可以如下解决:
# remotes::install_github("moodymudskipper/tag")
library(tag)
deco <- tag(args = list(.first = NULL, .last = NULL), pattern = {
t_args <- T_ARGS() # fetch arguments fed to tag
eval.parent(t_args[[".first"]]) # run .first arg
on.exit(eval.parent(t_args[[".last"]])) # run .last arg on exit
CALL() # run main call
})
foo <- function(x, y) {Sys.sleep(1); x + y} # sleep 1 sec to highlight expected behavior
deco(quote(message("calling foo")), quote(message("done")))$foo(1, 2)
#> calling foo
#> done
#> [1] 3
foo2 <- deco(quote(message("calling foo")), quote(message("done")))$foo
foo2(1, 2)
#> calling foo
#> done
#> [1] 3
deco2 <- deco(quote(message("calling foo")), quote(message("done")))
deco2$foo(1, 2)
#> calling foo
#> done
#> [1] 3
由reprex package(v0.3.0)于2020-01-30创建
标签是函数运算符工厂(或副词工厂),此处deco
是标签,而deco(quote(message("calling foo")), quote(message("done")))
是副词,带有$
的方法。这意味着您可以运行deco(quote(message("calling foo")), quote(message("done")))(foo)(1,2)
,但是美元符号使它更友好。
标记定义具有默认参数(默认值是强制性的,不支持点),并且使用特殊功能pattern
,{{1 }},T_ARGS()
,F_ARGS()
和F_ARGS()
来访问标记或函数的参数或形式以及调用本身(请参见F_FORMALS()
)。
实现了更多的魔术,因此可以将标记的参数赋予标记函数本身,因此也可以执行以下操作:
CALL()
在这些情况下,您可以在RStudio中享受自动完成功能:
更多信息:https://github.com/moodymudskipper/tag 软件包tags包含此类“装饰器”的集合