将作为参数传递给函数的函数名称获取

4

背景

将一个函数作为参数传递给另一个函数。该问题涉及到:

  • 获取该函数的名称,并以字符串形式方便后续操作
  • 定位该函数所在的程序包以进行调用
  • 理解:::::的调用方式

示例

函数fun_tst在变量x上执行函数FUN

fun_tst <- function(x = 1:100, FUN = mean) {
    return(FUN(x))
}

mean

fun_tst()
# [1] 50.5

sum

fun_tst(x = 1:1e3, FUN = sum)
# [1] 500500

问题

fun_tst <- function(x = 1:100, FUN = mean) {
    msg <- paste("Executing function", FUN)
    print(msg)
    return(FUN(x))
} 


fun_tst(x = 1:1e3, FUN = sum)

在执行paste("Executing function", FUN)时出错:无法将类型“builtin”强制转换为类型“字符”的向量


尝试

1)

有趣的是,print可以处理FUN对象,但结果会返回函数体。

fun_tst <- function(x = 1:100, FUN = mean) {
    print(FUN)
    return(FUN(x))
} 


fun_tst(x = 1:1e3, FUN = sum)

函数(...,na.rm = FALSE).Primitive("sum") [1] 500500

2)substitute

fun_tst <- function(x = 1:100, FUN = mean) {
    fun_name <- substitute(FUN)
    msg <- paste("Executing function", fun_name, collapse = " ")
    print(msg)
    return(FUN(x))
} 


fun_tst(x = 1:1e3, FUN = sum)

>> fun_tst(x = 1:1e3, FUN = sum)
[1] "Executing function sum"
[1] 500500

接近成功,但是当与::一起使用时,它看起来像一团糟:

>> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
[1] "Executing function :: Executing function dplyr Executing function glimpse"
 int [1:1000] 1 2 3 4 5 6 7 8 9 10 ..

期望的结果

fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
# Executing function glimpse from package dplyr
int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...

fun_tst(x = 1:1e3, FUN = sum)
# Executing function sum from package base

如何获取当前函数的名称?可能相关的链接:http://r.789695.n4.nabble.com/How-to-get-name-of-current-function-td879084.html 和 https://dev59.com/C2w05IYBdhLWcg3wVgWm - Frank
另一个选项是将函数名作为字符传递,打印名称,然后使用evalparse调用函数。 - Frank
@Frank 谢谢,听起来是一个明智的建议。我希望也许有一种简单的方法可以"钓出"函数命名空间(包)和它的名称,而不需要反解析然后再次解析... - Konrad
1
第一条评论中的死链接应该是"如何获取当前函数的名称?" - Frank
2个回答

5
你已经接近成功,第二次尝试使用substitute函数。问题在于R将language对象转换为字符的方式。
> as.character(substitute(dplyr::glimpse))
[1] "::"      "dplyr"   "glimpse" 

考虑到这一点,paste把它搞砸也就不奇怪了。我建议需要分别处理这两种情况来解决问题:
fun_tst <- function(x = 1:100, FUN = mean) {
  fun_name <- substitute(FUN)
  if (length(fun_name) == 1) {
    msg <- paste("Executing function", fun_name, "from package base")
  } else {
    msg <- paste("Executing function", fun_name[3], "from package", fun_name[2])
  }
  print(msg)
  return(FUN(x))
} 

这在你提供的两个示例中都适用:
> fun_tst(x = 1:1e3, FUN = sum)
[1] "Executing function sum from package base"
[1] 500500
> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
[1] "Executing function glimpse from package dplyr"
 int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...

然而,按照目前的写法,它会认为全局环境中的所有函数都来自 base 包,即使这些函数是用户定义的或者是通过 library 调用引入的。如果这符合您的使用情况,请不要明确指定“来自 base 包”。


4
如果您使用 deparse()substitute,您将获得所需的输出。请参阅有关将变量名传递给 plot() 的类似帖子:https://dev59.com/3mkw5IYBdhLWcg3wwdQS#9666650
fun_tst <- function(x = 1:100, FUN = mean) {
  message(paste("Executing function",deparse(substitute(FUN))))
  return((FUN(x)))
}
> fun_tst(x = 1:1e3, FUN = sum)
Executing function sum
[1] 500500

> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
Executing function dplyr::glimpse
 int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...

如果你更喜欢将消息作为字符向量,将message替换为print


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接