Określ nazwę funkcji w ramach tej funkcji


15

Jak mogę uzyskać nazwę funkcji w ramach tej nieanonimowej funkcji? poniżej zakładam, że istnieje funkcja lub proces do wykonania tego wywołania magical_r_function()i jakie są oczekiwane wyniki.

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"

Odpowiedzi:


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

Próbny:

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"

Tyler, na pewno mi to nie przeszkadza (i GG też jest dobre), ale jakie były twoje kryteria dla jakiej odpowiedzi wybrać?
— r2evans

Dobre pytanie. Oba doskonałe wybory. Oba wydawały się działać tak samo w moich testach. GG podał trochę więcej szczegółów. Trudno było podjąć decyzję.
— Tyler Rinker

Po bliższym zbadaniu ostatniego warunku przypisania funkcji do nowej nazwy, ta bardziej ściśle dopasowuje się do pierwotnego zapytania.
— Tyler Rinker

Proszę nie zmieniać wyłącznie mojego komentarza! Nie jestem wankingiem i nie potrzebuję powtórzeń (choć wszyscy macie trochę więcej niż ja). Nie, byłem po prostu ciekawy. Myślę, że zarówno match.calli sys.callsą ważne funkcje bazowe, nieznacznie różniące się „efektu” i „wymagania”. Byłem więc ciekawy wglądu, jaki możesz mieć w preferowaniu jednego od drugiego.
— r2evans

12

Spróbuj, sys.call(0)jeśli wynik obiektu wywołania jest poprawny lub usuń go, jeśli chcesz, aby nazwa była ciągiem znaków. Poniżej znajduje się kilka testów tego. sys.call zwraca zarówno nazwę, jak i argumenty, a [[1]] wybiera tylko nazwę.

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

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Nazwy funkcji

Pamiętaj, że funkcje w rzeczywistości nie mają nazw. To, co uważamy za nazwy funkcji, jest w rzeczywistości tylko zmiennymi, które przechowują funkcję i nie są częścią samej funkcji. Funkcja składa się z argumentów, treści i środowiska - wśród tych składników nie ma nazwy funkcji.

Funkcje anonimowe

Ponadto można mieć anonimowe funkcje, które mogą zwracać dziwne wyniki, jeśli zostaną użyte powyżej.

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

Skrzynie na brzeg

Istnieją pewne sytuacje, w szczególności związane z funkcjami anonimowymi, w których deparsezwróci więcej niż jeden element, więc jeśli chcesz uwzględnić takie przypadki krawędzi, użyj argumentu nlines = 1, aby przeprowadzić deparse lub użyć deparse (...) [[1]] lub jako wspomniane przez @Konrad Rudolph przy użyciu deparse1 w 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]])"

Inny

Przypomnijmy . Jeśli chcesz, aby nazwa funkcji wywoływała funkcję rekurencyjnie, użyj Recall()zamiast tego. Z pliku pomocy:

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

ostrzeżenie i zatrzymanie Oba wydają nazwę funkcji wraz z przekazanym im argumentem, więc nie ma potrzeby uzyskiwania bieżącej nazwy funkcji.

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

2
Twój „przypadek na krawędzi” został elegancko rozwiązany w wersji R 4.0 dzięki wprowadzeniu tej deparse1funkcji. Domyślam się, że powinniśmy zacząć używać tego zamiast deparsedomyślnie, gdy adopcja będzie wystarczająco wysoka.
— Konrad Rudolph

+1 za Recall, co według mnie jest tym, czego OP naprawdę potrzebował. Jednak Twój przykład sekwencji Fibonacciego nie jest tak naprawdę jeden dobry: ma ten problem, że często powtarzać połączenia: za fib(10), fib(8)nazywa się 2 razy w sumie (raz przez fib(10)bezpośrednio, raz przez fib(9)), fib(7)nazywany jest 3 razy, fib(6)nazywa się 5 razy. Widzisz dokąd to zmierza?
— Emil Bode

@Emil, jest to bezpośrednio ze strony pomocy Recall (jak podano w odpowiedzi), więc z pewnością ilustruje to. Jeśli nie podoba ci się to z innych powodów, możesz złożyć skargę do programistów R.
— G. Grothendieck

5

Możemy również użyć

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

my_fun()
#[1] "my_fun"
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.