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"
Tyler Rinker
źródło

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"
r2evans
źródło
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
G. Grothendieck
źródło
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"
akrun
źródło