Bestimmen Sie den Funktionsnamen innerhalb dieser Funktion

15

Wie kann ich den Funktionsnamen innerhalb dieser nicht anonymen Funktion ermitteln? Ich gehe davon aus, dass es eine Funktion oder einen Prozess gibt, um dies zu tun, magical_r_function()und wie die erwarteten Ausgaben aussehen würden.

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
quelle

Antworten:

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

Demo:

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
quelle
Tyler, es macht mir sicherlich nichts aus (und GGs sind auch gut), aber was waren Ihre Kriterien für welche Antwort Sie wählen sollten?
R2evans
Gute Frage. Beide ausgezeichnete Wahl. Beide schienen in meinen Tests gleich zu funktionieren. GGs lieferten etwas mehr Details. Es war schwer zu entscheiden.
Tyler Rinker
Bei näherer Betrachtung stimmt die letzte Bedingung des Zuweisens einer Funktion zu einem neuen Namen enger mit der ursprünglichen Frage überein.
Tyler Rinker
Bitte ändern Sie nicht nur meinen Kommentar! Ich wichse nicht und brauche Wiederholungen (obwohl ihr ein bisschen mehr habt als ich). Nein, ich war nur neugierig. Ich denke beides match.callund sys.callsind gültige Basisfunktionen mit wenig Unterschied in "Wirkung" und "Anforderungen". Ich war also neugierig auf Einsichten, die Sie haben könnten, wenn Sie einander vorziehen.
R2evans
12

Versuchen Sie, sys.call(0)ob die Ausgabe eines Aufrufobjekts in Ordnung ist, oder versuchen Sie es, wenn Sie den Namen nur als Zeichenfolge verwenden möchten. Im Folgenden finden Sie einige Tests dazu. sys.call gibt sowohl den Namen als auch die Argumente zurück und [[1]] wählt nur den Namen aus.

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

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Funktionsnamen

Beachten Sie, dass Funktionen eigentlich keine Namen haben. Was wir als Funktionsnamen betrachten, sind eigentlich nur Variablen, die die Funktion enthalten und nicht Teil der Funktion selbst sind. Eine Funktion besteht aus Argumenten, Text und einer Umgebung - unter diesen Bestandteilen gibt es keinen Funktionsnamen.

Anonyme Funktionen

Darüber hinaus kann man anonyme Funktionen haben und diese können seltsame Ergebnisse liefern, wenn sie mit den oben genannten verwendet werden.

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

Randfälle

Es gibt einige Situationen, insbesondere bei anonymen Funktionen, in denen deparsemehr als ein Element zurückgegeben wird. Wenn Sie also solche Randfälle abdecken möchten, verwenden Sie das Argument nlines = 1, um deparse (...) [[1]] oder as zu deparieren Erwähnt von @Konrad Rudolph unter Verwendung von deparse1 in 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]])"

Andere

Rückruf . Wenn der Grund dafür ist, dass der Funktionsname rekursiv aufgerufen wird, verwenden Sie Recall()stattdessen. Aus der Hilfedatei:

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

Warnung und Stopp Beide geben den Namen der Funktion zusammen mit dem an sie übergebenen Argument aus, sodass der aktuelle Funktionsname nicht abgerufen werden muss.

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X
G. Grothendieck
quelle
2
Ihr „Randfall“ wird in R 4.0 durch die Einführung der deparse1Funktion elegant gelöst . Ich vermute, wir sollten damit beginnen, anstatt deparsestandardmäßig, sobald die Akzeptanz hoch genug ist.
Konrad Rudolph
+1 für Recall, was OP meiner Meinung nach wirklich brauchte. Jedoch Ihr Beispiel der Sequenz Fibonacci ist nicht wirklich ein guter: es hat das Problem , dass man oft die Anrufe wiederholen: für fib(10), fib(8)insgesamt 2 - mal aufgerufen (einmal fib(10)direkt, einmal durch fib(9)),fib(7) 3 - mal aufgerufen wird, fib(6)heißt 5 mal. Sehen Sie, wohin das führt?
Emil Bode
@Emil, Dies ist direkt von der Rückruf-Hilfeseite (wie in der Antwort angegeben), so dass es den Punkt sicherlich veranschaulicht. Wenn es Ihnen aus anderen Gründen nicht gefällt, können Sie sich bei den R-Entwicklern beschweren.
G. Grothendieck
5

Wir können auch verwenden

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

my_fun()
#[1] "my_fun"
akrun
quelle