2011-08-05 18 views
11

Estoy tratando de encontrar una contraparte global en isdebugged() en R. Mi hipótesis es que tengo funciones que hacen llamadas a otras funciones, todas las cuales he escrito, y estoy convirtiendo debug() activado y desactivado para diferentes funciones durante la depuración. Sin embargo, puedo perder la pista de las funciones que se configuran para ser depuradas. Cuando me olvido y empiezo un ciclo, puedo obtener un rendimiento mucho mayor (molestia, pero no terrible) o puedo obtener ningún resultado cuando se desea (mal).Funciones de listado con indicador de depuración establecido en R

Mi enfoque actual es utilizar una función similar a la siguiente, y puedo llamarla con listDebugged(ls()) o listar los elementos en una biblioteca cargada (ejemplos a continuación). Esto podría ser suficiente, pero requiere que lo llame con la lista de cada función en el espacio de trabajo o en los paquetes que se cargan. Puedo ajustar otra función que los obtenga. Parece que debería haber una forma más sencilla de simplemente "preguntar" a la función de depuración o consultar alguna parte oscura del entorno donde se esconde la lista de funciones con el indicador de depuración establecido.

Por lo tanto, una pregunta de dos partes:

  1. ¿Hay una llamada más simple que existe para consultar las funciones con el indicador de depuración?
  2. Si no, ¿hay algún truco que haya pasado por alto? Por ejemplo, si una función en un paquete enmascara a otra, sospecho que puedo devolver un resultado engañoso.

que dan cuenta de que hay otro método que podría tratar y que es envolver debug y undebug dentro de las funciones que también mantienen una lista de nombres de funciones oculto depuradas. Todavía no estoy convencido de que sea algo seguro de hacer.

ACTUALIZACIÓN (5/08/11): Busqué SO, y no encontré las preguntas anteriores. Sin embargo, la lista de "preguntas relacionadas" de SO ha mostrado que an earlier question that is similar, aunque la función en la respuesta para esa pregunta es a la vez más detallada y más lenta que la función ofrecida por @cbeleites. La pregunta anterior tampoco proporciona ningún código, mientras que yo sí. :)

El código:

listDebugged <- function(items){ 
    isFunction <- vector(length = length(items)) 
    isDebugged <- vector(length = length(items)) 

    for(ix in seq_along(items)){ 
     isFunction[ix] <- is.function(eval(parse(text = items[ix]))) 
    } 

    for(ix in which(isFunction == 1)){ 
     isDebugged[ix] <- isdebugged(eval(parse(text = items[ix]))) 
    } 
    names(isDebugged) <- items 
    return(isDebugged) 
} 

# Example usage 
listDebugged(ls()) 
library(MASS) 
debug(write.matrix) 
listDebugged(ls("package:MASS")) 
+0

En la base R, no hay forma de hacer ese trabajo más que envolviendo la función 'debug'. – kohske

Respuesta

6

Aquí está mi tiro en la función listDebugged:

ls.deb <- function(items = search()){ 
    .ls.deb <- function (i){ 
    f <- ls (i) 
    f <- mget (f, as.environment (i), mode = "function", 

       ## return a function that is not debugged 
       ifnotfound = list (function (x) function() NULL) 
       ) 

    if (length (f) == 0) 
     return (NULL) 

    f <- f [sapply (f, isdebugged)] 
    f <- names (f) 

    ## now check whether the debugged function is masked by a not debugged one 
    masked <- !sapply (f, function (f) isdebugged (get (f))) 

    ## generate pretty output format: 
    ## "package::function" and "(package::function)" for masked debugged functions 
    if (length (f) > 0) { 
     if (grepl ('^package:', i)) { 
     i <- gsub ('^package:', '', i) 
     f <- paste (i, f, sep = "::") 
     } 

     f [masked] <- paste ("(", f [masked], ")", sep = "") 

     f 
    } else { 
     NULL 
    } 
    } 


    functions <- lapply (items, .ls.deb) 
    unlist (functions) 
} 
  • elegí un nombre diferente, como el formato de salida son sólo las funciones depuradas (de lo contrario Obtuve fácilmente miles de funciones)
  • la salida tiene el formato package::function (o más bien namespace::function pero los paquetes tendrán n amespaces muy pronto de todos modos).
  • si se enmascara la función depurado, la salida es "(package::function)"
  • el valor por defecto está buscando throught toda la ruta de búsqueda
+0

+1 Esto es bueno y parece funcionar. Lo estoy recorriendo ahora, para saber qué está haciendo con 'f'. Inteligente. – Iterator

+0

Supervisión de mi parte: avanzar con 'debug()' es una mejor manera de aprender lo que está haciendo. El mejor uso de 'debug' aún. :) – Iterator

+0

Gracias! Aprendí varias funciones e ideas nuevas de esta función. – Iterator

2

Dado que la pregunta original, que he estado buscando más y más en Mark Bravington's debug package. Si usa ese paquete, entonces check.for.traces() es el comando apropiado para enumerar aquellas funciones que se están depurando a través del mtrace.

El paquete de depuración vale la pena si uno está pasando mucho tiempo con el depurador R y varias opciones trace.

1

@cbeleites Me gusta su respuesta, pero no funcionó para mí. Tengo que esto funcione, pero es menos funcional que la suya por encima (no cheques recursivas, sin impresión bonita)

require(plyr) 
debug.ls <- function(items = search()){ 
    .debug.ls <- function(package){ 
    f <- ls(package) 
    active <- f[which(aaply(f, 1, function(x){ 
     tryCatch(isdebugged(x), error = function(e){FALSE}, finally=FALSE) 
     }))] 
    if(length(active)==0){ 
     return(NULL) 
    } 
    active 
    } 

    functions <- lapply (items, .debug.ls) 
    unlist (functions) 
} 
0

constantemente quedan atrapados en el marco de browser ventana porque de no undebug funciones. Así que he creado dos funciones y las he agregado a mi .Rprofile. Las funciones de ayuda son bastante sencillas.

require(logging) 

# Returns a vector of functions on which the debug flag is set 
debuggedFuns <- function() { 
    envs <- search() 
    debug_vars <- sapply(envs, function(each_env) { 
    funs <- names(Filter(is.function, sapply(ls(each_env), get, each_env))) 
    debug_funs <- Filter(isdebugged, funs) 
    debug_funs 
    }) 
    return(as.vector(unlist(debug_vars))) 
} 

# Removes the debug flag from all the functions returned by `debuggedFuns` 
unDebugAll <- function(verbose = TRUE) { 
    toUnDebug <- debuggedFuns() 
    if (length(toUnDebug) == 0) { 
    if (verbose) loginfo('no Functions to `undebug`') 
    return(invisible()) 
    } else { 
    if (verbose) loginfo('undebugging [%s]', paste0(toUnDebug, collapse = ', ')) 
    for (each_fn in toUnDebug) { 
     undebug(each_fn) 
    } 
    return(invisible()) 
    } 
} 

Los he probado y funciona bastante bien. ¡Espero que esto ayude!

2

Este es un simple de una sola línea usando lsf.str:

which(sapply(lsf.str(), isdebugged)) 

Puede cambiar ambientes dentro de la función, ver ?lsf.str para más argumentos.

+0

Un ejemplo de esto que comprueba todas las funciones adjuntas: 'names (which (sapply (unlist (lapply (search(), function (x) lsf.str (pos = x))), isdebugged)))' – jbaums

Cuestiones relacionadas