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


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.