Визначте ім'я функції в межах цієї функції


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"

Тайлер, я, звичайно, не проти (і GG теж хороший), але які були ваші критерії, яку відповідь вибрати?
r2evans

Хороше питання. Обидва чудові варіанти. На моїх тестах обидва працювали однаково. GG представив трохи більше деталей. Важко було вирішити.
Тайлер Рінкер

При більш детальному огляді останньої умови присвоєння функції новому імені це більше узгоджується з оригінальним запитом.
Тайлер Рінкер

Будь ласка, не змінюйте виключно мій коментар! Я не мучуся і не потребую повторень (хоча у вас є трохи більше, ніж у мене). Ні, мені було просто цікаво. Я думаю, що обидва 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

попередження та зупинка. Вони обидва видають ім'я функції разом з будь-яким аргументом, який передається їм, тому не потрібно отримувати поточну назву функції.

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, це прямо з довідкової сторінки нагадування (як зазначено у відповіді), тому це, безумовно, ілюструє суть. Якщо вам це не подобається з інших причин, ви можете подати скаргу розробникам R.
Г. Гротендік

5

Ми також можемо використовувати

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

my_fun()
#[1] "my_fun"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.