Определить имя функции в этой функции

15

Как я могу получить имя функции в этой неанонимной функции? ниже я предполагаю, что есть функция или процесс для этого 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"
Тайлер Ринкер
источник

Ответы:

18
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"
r2evans
источник
Тайлер, я, конечно, не против (и Г.Г. это тоже хорошо), но каков был твой критерий для выбора ответа?
r2evans
Хороший вопрос. Оба отличных варианта. Оба, похоже, работали одинаково в моих тестах. Г.Г. предоставил немного больше деталей. Было трудно решить.
Тайлер Ринкер
При ближайшем рассмотрении последнее условие присвоения функции новому имени более точно совпадает с исходным запросом.
Тайлер Ринкер
Пожалуйста, не меняйте только мой комментарий! Я не шучу и не нуждаюсь в повторениях (хотя у вас будет немного больше, чем у меня). Нет, мне было просто любопытно. Я думаю, что оба match.callи sys.callявляются действительными базовыми функциями с небольшой разницей в «эффекте» и «требованиях». Так что мне было любопытно понять, что вы можете предпочесть одно другому.
r2evans
12

Попробуйте, 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 (...) [[1]] или как упоминается @Konrad Rudolph при использовании deparse1 в R 4.0.0.

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

warning and stop Они оба выдают имя функции вместе с передаваемым им аргументом, поэтому нет необходимости получать текущее имя функции.

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X
Г. Гротендик
источник
2
Ваш «крайний случай» элегантно решен в R 4.0 посредством введения deparse1функции. Я предполагаю, что мы должны начать использовать это вместо deparseпо умолчанию, как только усыновление будет достаточно высоким.
Конрад Рудольф
+1 за то Recall, что я чувствую, что ОП действительно было нужно. Тем не менее, ваш пример последовательности Фибоначчи не очень хороший: у него есть проблема с тем, что вы часто повторяете вызовы: для fib(10), fib(8)вызывается всего 2 раза (один раз fib(10)напрямую, один раз fib(9)), fib(7)вызывается 3 раза, fib(6)вызывается 5 раз. Видишь, куда это идет?
Эмиль Боде
@ Emil, это прямо со страницы справки Recall (как указано в ответе), так что это, безусловно, иллюстрирует суть. Если вам это не нравится по другим причинам, вы можете пожаловаться разработчикам R.
Г. Гротендик
5

Мы также можем использовать

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

my_fun()
#[1] "my_fun"
akrun
источник