Determinar el nombre de la función dentro de esa función

15

¿Cómo puedo obtener el nombre de la función dentro de esa función no anónima? a continuación, supongo que hay una función o proceso para hacer esto llamado magical_r_function()y cuáles serían los resultados esperados.

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
fuente

Respuestas:

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

Manifestación:

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
fuente
Tyler, ciertamente no me importa (y GG también es bueno), pero ¿cuál fue su criterio para qué respuesta elegir?
r2evans
Buena pregunta. Ambas excelentes opciones. Ambos parecían funcionar igual en mis pruebas. GG ha proporcionado un poco más de detalle. Fue difícil de decidir.
Tyler Rinker
Tras una inspección más cercana, la última condición de asignar una función a un nuevo nombre, este se alinea más estrechamente con la pregunta original.
Tyler Rinker
¡Por favor no cambies únicamente en mi comentario! No me estoy masturbando y necesito repeticiones (aunque ustedes tienen un poco más que yo). No, solo tenía curiosidad. Creo que ambos match.cally sys.callson funciones básicas válidas con poca diferencia en "efecto" y "requisitos". Así que tenía curiosidad por saber qué podría tener al preferir uno sobre el otro.
r2evans
12

Pruebe sys.call(0)si la salida de un objeto de llamada está bien o descárguela si solo desea el nombre como una cadena de caracteres. A continuación hay un par de pruebas de esto. sys.call devuelve tanto el nombre como los argumentos y [[1]] selecciona solo el nombre.

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

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Nombres de funciones

Tenga en cuenta que las funciones en realidad no tienen nombres. Lo que consideramos como nombres de funciones en realidad son solo variables que contienen la función y no son parte de la función en sí. Una función consta de argumentos, cuerpo y un entorno; no existe un nombre de función entre esos constituyentes.

Funciones anónimas

Además, uno puede tener funciones anónimas y estas pueden devolver resultados extraños cuando se usa con lo anterior.

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

Casos de borde

Existen algunas situaciones, particularmente que involucran funciones anónimas, donde deparsedevolverá más de un elemento, por lo que si desea cubrir tales casos límite, use el argumento nlines = 1 para eliminar o utilizar la función de eliminación (...) [[1]] o como mencionado por @Konrad Rudolph al usar deparse1 en 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]])"

Otro

Recordar . Si la razón por la que desea el nombre de la función es llamarla recursivamente, use Recall()en su lugar Del archivo de ayuda:

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

advertencia y detener Ambos emiten el nombre de la función junto con cualquier argumento que se les pase, por lo que no es necesario obtener el nombre de la función actual.

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X
G. Grothendieck
fuente
2
Su "caso límite" se resuelve elegantemente en R 4.0 a través de la introducción de la deparse1función. Supongo que deberíamos comenzar a usar eso en lugar de hacerlo de deparseforma predeterminada, una vez que la adopción sea lo suficientemente alta.
Konrad Rudolph
+1 para Recall, lo que creo es lo que OP realmente necesitaba. Sin embargo, su ejemplo de la secuencia de Fibonacci no es realmente bueno: tiene el problema de que a menudo repite las llamadas: porque fib(10), fib(8)se llama 2 veces en total (una vez fib(10)directamente, una vez fib(9)), fib(7)se llama 3 veces, fib(6)se llama 5 veces. ¿Ves a dónde va esto?
Emil Bode
@Emil, esto es directamente desde la página de ayuda de recuperación (como se indica en la respuesta), por lo que sin duda ilustra el punto. Si no le gusta por otros motivos, puede quejarse con los desarrolladores de R.
G. Grothendieck
5

También podemos usar

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

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