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"

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"

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

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"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.