确定该函数中的函数名称


14

我如何在该非匿名函数中获取函数名称?在下面,我假设有一个函数或过程来执行此操作magical_r_function(),以及预期的输出结果。

my_fun <- function(){
      magical_r_function()
}
my_fun()
## [1] "my_fun"


foo_bar <- function(){
      magical_r_function()
}
foo_bar()
## [1] "foo_bar"

ballyhoo <- function(){
    foo_bar()
}
ballyhoo()
## [1] "foo_bar"

tom_foolery <- foo_bar
tom_foolery()
## [1] "tom_foolery"

Answers:


17
as.character(match.call()[[1]])

演示:

my_fun <- function(){
  as.character(match.call()[[1]])
}
my_fun()
# [1] "my_fun"
foo_bar <- function(){
  as.character(match.call()[[1]])
}
foo_bar()
# [1] "foo_bar"
ballyhoo <- function(){
  foo_bar()
}
ballyhoo()
# [1] "foo_bar"
tom_foolery <- foo_bar
tom_foolery()
# [1] "tom_foolery"

泰勒,我当然不介意(GG的也很好),但是您选择哪个答案的标准是什么?
r2evans

好问题。两者都是绝佳的选择。在我的测试中,两者似乎都工作相同。GG提供了更多细节。很难决定。
泰勒·林克

在仔细检查后,为新名称分配功能的最后条件是,此条件与原始要求更加一致。
泰勒·林克

请不要仅根据我的评论进行更改!我并不想做代表(尽管你们所有人都比我多得多)。不,我只是好奇。我认为match.callsys.call都是有效的基本函数,在“效果”和“需求”方面差异不大。因此,我很想知道您可能更喜欢一个而不是另一个。
r2evans

11

sys.call(0)如果您只想将该名称作为字符串,请尝试调用对象的输出是否正常,或者否决。以下是一些测试。sys.call返回名称和参数,[[1]]仅选择名称。

my_fun <- function() deparse(sys.call(0)[[1]])

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

功能名称

请注意,函数实际上没有名称。我们所谓的函数名称实际上只是保存函数的变量,而不是函数本身的一部分。函数由参数,主体和环境组成-在这些组成部分中没有函数名称。

匿名功能

此外,一个可以具有匿名函数,当与上述函数一起使用时,它们可能返回奇怪的结果。

sapply(1:3, function(x) deparse(sys.call(0)[[1]]))
## [1] "FUN" "FUN" "FUN"

边缘情况

确实存在某些情况,特别是涉及匿名函数的情况,这些情况deparse将返回多个元素,因此,如果要涵盖此类边缘情况,请使用nlines = 1参数进行deparse或使用deparse(...)[[1]]或as @Konrad Rudolph在R 4.0.0中使用deparse1提到。

Map(function(x) deparse(sys.call(0)[[1]], nlines = 1), 1:2)
## [[1]]
## [1] "function (x) "
## 
## [[2]]
## [1] "function (x) "

Map(function(x) deparse(sys.call(0)[[1]]), 1:2)  # without nlines=1
## [[1]]
## [1] "function (x) "             "deparse(sys.call(0)[[1]])"
##
## [[2]]
## [1] "function (x) "             "deparse(sys.call(0)[[1]])"

其他

回想一下。如果您想要函数名称的原因是递归调用函数,请Recall()改用。从帮助文件:

fib <- function(n)
   if(n<=2) { if(n>=0) 1 else 0 } else Recall(n-1) + Recall(n-2)
fib(4)
## [1] 3

警告和停止这两个命令都会发出函数名称以及传递给它们的任何参数,因此无需获取当前函数名称。

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X

2
通过引入该deparse1功能,可以在R 4.0中很好地解决您的“边缘保护套” 。我猜测deparse一旦采用率足够高,我们应该开始使用它而不是默认使用它。
康拉德·鲁道夫

为+1 Recall,我觉得这是O​​P真正需要的。但是,您的斐波那契数列示例实际上并不是一个很好的例子:它具有您经常重复调用的问题:for fib(10)fib(8)总共被调用2次(一次被fib(10)直接调用,一次被调用fib(9)),fib(7)被调用3次,fib(6)被调用5次。看到这是怎么回事?
Emil Bode

@Emil,这是正确的,位于Recall帮助页面(如答案中所述),因此可以肯定地说明了这一点。如果您不喜欢其他理由,可以向R开发人员投诉。
G. Grothendieck

5

我们也可以使用

my_fun <- function(){
  as.character(as.list(sys.calls()[[1]])[[1]])
 }

my_fun()
#[1] "my_fun"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.