Determina il nome della funzione all'interno di quella funzione


15

Come posso ottenere il nome della funzione all'interno di quella funzione non anonima? sotto suppongo che ci sia una funzione o un processo per fare questo chiamato magical_r_function()e quali sarebbero gli output previsti.

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"

Risposte:


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, di certo non mi dispiace (e anche quello di GG è buono), ma quali erano i tuoi criteri per quale risposta scegliere?
r2evans,

Buona domanda. Entrambe le scelte eccellenti. Entrambi sembravano funzionare allo stesso modo nei miei test. GG ha fornito ulteriori dettagli. È stato difficile decidere.
Tyler Rinker,

Ad un esame più attento l'ultima condizione di assegnazione di una funzione a un nuovo nome, questa si allinea maggiormente alla richiesta originale.
Tyler Rinker,

Per favore non cambiare solo sul mio commento! Non mi sto masturbando e non ho bisogno di ripetizioni (anche se tutti voi avete un po 'più di me). No, ero solo curioso. Penso entrambi match.calle sys.callsono valide funzioni di base con poca differenza in "effetto" e "requisiti". Quindi ero curioso di capire che potresti avere nel preferire l'uno all'altro.
r2evans,

12

Prova sys.call(0)se l'output di un oggetto call è ok o deparse se vuoi solo il nome come stringa di caratteri. Di seguito sono riportati un paio di test di questo. sys.call restituisce sia il nome che gli argomenti e [[1]] seleziona solo il nome.

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

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Nomi delle funzioni

Si noti che le funzioni in realtà non hanno nomi. Ciò che consideriamo nomi di funzioni sono in realtà solo variabili che contengono la funzione e non fanno parte della funzione stessa. Una funzione è composta da argomenti, corpo e un ambiente - non esiste un nome di funzione tra quei componenti.

Funzioni anonime

Inoltre si possono avere funzioni anonime e queste potrebbero restituire strani risultati se usate con quanto sopra.

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

Custodie per bordi

Esistono alcune situazioni, in particolare che coinvolgono funzioni anonime, in cui deparseverrà restituito più di un elemento, quindi se vuoi coprire tali casi limite usa l'argomento nlines = 1 per deparse o usa deparse (...) [[1]] o come menzionato da @Konrad Rudolph usando 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]])"

Altro

Recall . Se il motivo per cui si desidera il nome della funzione è chiamare ricorsivamente la funzione, utilizzare Recall()invece. Dal file di aiuto:

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

avviso e arresto Entrambi forniscono il nome della funzione insieme a qualunque argomento gli venga passato, quindi non è necessario ottenere il nome della funzione corrente.

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

2
Il tuo "caso limite" è risolto elegantemente in R 4.0 tramite l'introduzione della deparse1funzione. Immagino che dovremmo iniziare a usarlo anziché deparseper impostazione predefinita, una volta che l'adozione è abbastanza alta.
Konrad Rudolph,

+1 per Recall, che ritengo sia ciò di cui OP aveva davvero bisogno. Tuttavia, il tuo esempio della sequenza di Fibonacci non è davvero buono: ha il problema che spesso ripeti le chiamate: perché fib(10), fib(8)viene chiamato 2 volte in totale (una volta fib(10)direttamente, una volta fib(9)), fib(7)viene chiamato 3 volte, fib(6)viene chiamato 5 volte. Vedi dove sta andando?
Emil Bode,

@Emil, questo è direttamente dalla pagina di aiuto di richiamo (come indicato nella risposta), quindi illustra sicuramente il punto. Se non ti piace per altri motivi, puoi lamentarti con gli sviluppatori R.
G. Grothendieck,

5

Possiamo anche usare

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

my_fun()
#[1] "my_fun"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.