¿Cómo puedo ver el código fuente de una función?

Quiero ver el código fuente de una función para ver cómo funciona. Sé que puedo imprimir una función escribiendo su nombre en el mensaje:

> t function (x) UseMethod("t")   

En este caso, ¿qué significa UseMethod("t") ? ¿Cómo puedo encontrar el código fuente que realmente está usando, por ejemplo: t(1:10) ?

¿Hay alguna diferencia entre cuando veo UseMethod y cuando veo standardGeneric y showMethods , como con with ?

 > with standardGeneric for "with" defined from package "base" function (data, expr, ...) standardGeneric("with")   Methods may be defined for arguments: data Use showMethods("with") for currently available ones. 

En otros casos, puedo ver que se están llamando a las funciones R, pero no puedo encontrar el código fuente para esas funciones.

 > ts.union function (..., dframe = FALSE) .cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)   > .cbindts Error: object '.cbindts' not found > .makeNamesTs Error: object '.makeNamesTs' not found 

¿Cómo encuentro funciones como .cbindts y .makeNamesTs ?

En otros casos, hay un poco de código R, pero la mayor parte del trabajo parece realizarse en otro lugar.

 > matrix function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) { if (is.object(data) || !is.atomic(data)) data <- as.vector(data) .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), missing(ncol))) }   > .Internal function (call) .Primitive(".Internal") > .Primitive function (name) .Primitive(".Primitive") 

¿Cómo .Primitive qué hace la función .Primitive ? De forma similar, algunas funciones llaman .C , .Call , .Fortran , .External o .Internal . ¿Cómo puedo encontrar el código fuente para esos?

UseMethod("t") te dice que t() es una función genérica ( S3 ) que tiene métodos para diferentes clases de objetos.

El sistema de envío del método S3

Para las clases S3, puede usar la función de methods para enumerar los métodos para una clase o función genérica particular.

 > methods(t) [1] t.data.frame t.default t.ts* Non-visible functions are asterisked > methods(class="ts") [1] aggregate.ts as.data.frame.ts cbind.ts* cycle.ts* [5] diffinv.ts* diff.ts kernapply.ts* lines.ts [9] monthplot.ts* na.omit.ts* Ops.ts* plot.ts [13] print.ts time.ts* [< -.ts* [.ts* [17] t.ts* window<-.ts* window.ts* Non-visible functions are asterisked 

"Las funciones no visibles están marcadas con un asterisco" significa que la función no se exporta desde el espacio de nombres de su paquete. Todavía puede ver su código fuente a través de la función ::: (es decir, stats:::t.ts ), o mediante el uso de getAnywhere() . getAnywhere() es útil porque no tiene que saber de qué paquete proviene la función.

 > getAnywhere(t.ts) A single object matching 't.ts' was found It was found in the following places registered S3 method for t from namespace stats namespace:stats with value function (x) { cl < - oldClass(x) other <- !(cl %in% c("ts", "mts")) class(x) <- if (any(other)) cl[other] attr(x, "tsp") <- NULL t(x) }   

El sistema de despacho del método S4

El sistema S4 es un sistema de despacho de métodos más nuevo y es una alternativa al sistema S3. Aquí hay un ejemplo de una función S4:

 > library(Matrix) Loading required package: lattice > chol2inv standardGeneric for "chol2inv" defined from package "base" function (x, ...) standardGeneric("chol2inv")   Methods may be defined for arguments: x Use showMethods("chol2inv") for currently available ones. 

El resultado ya ofrece mucha información. standardGeneric es un indicador de una función S4. El método para ver los métodos S4 definidos se ofrece amablemente:

 > showMethods(chol2inv) Function: chol2inv (package base) x="ANY" x="CHMfactor" x="denseMatrix" x="diagonalMatrix" x="dtrMatrix" x="sparseMatrix" 

getMethod se puede usar para ver el código fuente de uno de los métodos:

 > getMethod("chol2inv", "diagonalMatrix") Method Definition: function (x, ...) { chk.s(...) tcrossprod(solve(x)) }   Signatures: x target "diagonalMatrix" defined "diagonalMatrix" 

También hay métodos con firmas más complejas para cada método, por ejemplo

 require(raster) showMethods(extract) Function: extract (package raster) x="Raster", y="data.frame" x="Raster", y="Extent" x="Raster", y="matrix" x="Raster", y="SpatialLines" x="Raster", y="SpatialPoints" x="Raster", y="SpatialPolygons" x="Raster", y="vector" 

Para ver el código fuente de uno de estos métodos, se debe suministrar la firma completa, por ej.

 getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") ) 

No será suficiente proporcionar la firma parcial

 getMethod("extract",signature="SpatialPolygons") #Error in getMethod("extract", signature = "SpatialPolygons") : # No method found for function "extract" and signature SpatialPolygons 

Funciones que llaman a funciones no exportadas

En el caso de ts.union , .cbindts y .makeNamesTs son funciones no .makeNamesTs del espacio de nombres de stats . Puede ver el código fuente de las funciones no getAnywhere utilizando el operador ::: o getAnywhere .

 > stats:::.makeNamesTs function (...) { l < - as.list(substitute(list(...)))[-1L] nm <- names(l) fixup <- if (is.null(nm)) seq_along(l) else nm == "" dep <- sapply(l[fixup], function(x) deparse(x)[1L]) if (is.null(nm)) return(dep) if (any(fixup)) nm[fixup] <- dep nm }   

Funciones que llaman a código comstackdo

Tenga en cuenta que "comstackdo" no hace referencia al código R comstackdo en bytes creado por el paquete del comstackdor . La línea en la salida anterior indica que la función está comstackda en bytes, y aún puede ver la fuente desde la línea de comando R.

Las funciones que llaman .C , .Call , .Fortran , .External , .Internal o .Primitive están llamando a los puntos de entrada en el código comstackdo, por lo que tendrá que consultar las fonts del código comstackdo si desea comprender completamente la función. Este espejo GitHub del código fuente R es un buen lugar para comenzar. La función pryr::show_c_source puede ser una herramienta útil, ya que lo llevará directamente a una página de GitHub para llamadas .Internal y .Primitive . Los paquetes pueden usar .C , .Call , .Fortran y .External ; pero no .Internal o .Primitive , porque estos se utilizan para llamar a funciones integradas en el intérprete R.

Las llamadas a algunas de las funciones anteriores pueden usar un objeto en lugar de una cadena de caracteres para hacer referencia a la función comstackda. En esos casos, el objeto es de clase "NativeSymbolInfo" , "RegisteredNativeSymbol" o "NativeSymbol" ; e imprimir el objeto produce información útil. Por ejemplo, optim llama .External2(C_optimhess, res$par, fn1, gr1, con) (tenga en cuenta que es C_optimhess , no "C_optimhess" ). optim está en el paquete de estadísticas, por lo que puede escribir stats:::C_optimhess para ver información sobre la función comstackda que se está llamando.

Código comstackdo en un paquete

Si desea ver el código comstackdo en un paquete, deberá descargar / descomprimir el origen del paquete. Los binarios instalados no son suficientes. El código fuente de un paquete está disponible desde el mismo repository CRAN (o compatible con CRAN) desde donde se instaló originalmente el paquete. La función download.packages() puede obtener el origen del paquete por usted.

 download.packages(pkgs = "Matrix", destdir = ".", type = "source") 

Esto descargará la versión de origen del paquete Matrix y guardará el archivo .tar.gz correspondiente en el directorio actual. El código fuente para las funciones comstackdas se puede encontrar en el directorio src del archivo descomprimido y no almacenado. El paso de descompresión e inactivación se puede realizar fuera de R o desde dentro de R utilizando la función untar() . Es posible combinar el paso de descarga y expansión en una sola llamada (tenga en cuenta que solo se puede descargar y desempaquetar un paquete a la vez):

 untar(download.packages(pkgs = "Matrix", destdir = ".", type = "source")[,2]) 

Alternativamente, si el desarrollo del paquete se realiza de forma pública (por ejemplo, a través de GitHub , R-Forge o RForge.net ), probablemente pueda navegar por el código fuente en línea.

Código comstackdo en un paquete base

Ciertos paquetes se consideran paquetes "base". Estos paquetes se envían con R y su versión está bloqueada a la versión de R. Los ejemplos incluyen base , compiler , stats y utils . Como tal, no están disponibles como paquetes descargables por separado en CRAN como se describe anteriormente. Por el contrario, son parte del árbol fuente R en los directorios de paquetes individuales en /src/library/ . Cómo acceder a la fuente R se describe en la siguiente sección.

Código comstackdo incorporado en el intérprete R

Si desea ver el código incorporado en el intérprete R, deberá descargar / descomprimir las fonts R; o puede ver las fonts en línea a través del repository R Subversion o el espejo github de Winston Chang .

El artículo de noticias R de Uwe Ligges (PDF) (página 43) es una buena referencia general de cómo ver el código fuente de las funciones .Internal y .Primitive . Los pasos básicos son buscar primero el nombre de la función en src/main/names.c y luego buscar el nombre "C-entry" en los archivos en src/main/* .

Además de las otras respuestas sobre esta pregunta y sus duplicados, esta es una buena forma de obtener el código fuente para una función de paquete sin necesidad de saber en qué paquete está. Por ejemplo, si queremos la fuente para randomForest::rfcv() :

Para verlo / editarlo en una ventana emergente:

 edit(getAnywhere('rfcv'), file='source_rfcv.r') 

Para redirigir a un archivo separado :

 capture.output(getAnywhere('rfcv'), file='source_rfcv.r') 

Se revela cuando depura usando la función debug (). Supongamos que desea ver el código subyacente en la función de transposición t (). Simplemente escribiendo ‘t’, no revela mucho.

 >t function (x) UseMethod("t")   

Pero, al usar ‘depurar (nombreDeFunción)’, revela el código subyacente, sin las partes internas.

 > debug(t) > t(co2) debugging in: t(co2) debug: UseMethod("t") Browse[2]> debugging in: t.ts(co2) debug: { cl < - oldClass(x) other <- !(cl %in% c("ts", "mts")) class(x) <- if (any(other)) cl[other] attr(x, "tsp") <- NULL t(x) } Browse[3]> debug: cl < - oldClass(x) Browse[3]> debug: other < - !(cl %in% c("ts", "mts")) Browse[3]> debug: class(x) < - if (any(other)) cl[other] Browse[3]> debug: attr(x, "tsp") < - NULL Browse[3]> debug: t(x) 

EDITAR: debugonce () logra lo mismo sin tener que usar undebug ()

No vi cómo encaja esto en el flujo de la respuesta principal, pero me dejó perplejo por un tiempo, así que lo estoy agregando aquí:

Operadores Infix

Para ver el código fuente de algunos operadores base infijo (por ejemplo, %% , %*% , %in% ), use getAnywhere , por ejemplo:

 getAnywhere("%%") # A single object matching '%%' was found # It was found in the following places # package:base # namespace:base # with value # # function (e1, e2) .Primitive("%%") 

La respuesta principal cubre cómo usar espejos para cavar más profundo.

Para funciones no primitivas, R base incluye una función llamada body() que devuelve el cuerpo de la función. Por ejemplo, se puede ver la fuente de la función print.Date() :

 body(print.Date) 

producirá esto:

 { if (is.null(max)) max < - getOption("max.print", 9999L) if (max < length(x)) { print(format(x[seq_len(max)]), max = max, ...) cat(" [ reached getOption(\"max.print\") -- omitted", length(x) - max, "entries ]\n") } else print(format(x), max = max, ...) invisible(x) } 

Si está trabajando en un script y desea el código de la función como un vector de caracteres, puede obtenerlo.

 capture.output(print(body(print.Date))) 

lo conseguirá:

 [1] "{" [2] " if (is.null(max)) " [3] " max < - getOption(\"max.print\", 9999L)" [4] " if (max < length(x)) {" [5] " print(format(x[seq_len(max)]), max = max, ...)" [6] " cat(\" [ reached getOption(\\\"max.print\\\") -- omitted\", " [7] " length(x) - max, \"entries ]\\n\")" [8] " }" [9] " else print(format(x), max = max, ...)" [10] " invisible(x)" [11] "}" 

¿Por qué querría hacer tal cosa? Estaba creando un objeto S3 personalizado ( x , donde class(x) = "foo" ) basado en una lista. Uno de los miembros de la lista (llamado "diversión") era una función y yo quería print.foo() para mostrar el código fuente de la función, sangrado. Así que terminé con el siguiente fragmento en print.foo() :

 sourceVector = capture.output(print(body(x[["fun"]]))) cat(paste0(" ", sourceVector, "\n")) 

que sangra y muestra el código asociado con x[["fun"]] .

Hay una función muy útil en R edit

 new_optim < - edit(optim) 

optim el código fuente de optim usando el editor especificado en las options de R, y luego podrá editarlo y asignar la función modificada a new_optim . Me gusta mucho esta función para ver el código o para depurar el código, por ejemplo, imprimir algunos mensajes o variables o incluso asignarlos a variables globales para una mayor investigación (por supuesto, puede usar la debug ).

Si solo desea ver el código fuente y no desea que se imprima el molesto código fuente largo en su consola, puede usar

 invisible(edit(optim)) 

Claramente, esto no se puede usar para ver el código fuente de C / C ++ o Fortran.

Por cierto, la edit puede abrir otros objetos como lista, matriz, etc., que luego muestra la estructura de datos con atributos también. La función de se puede usar para abrir un editor de Excel (si la GUI lo admite) para modificar la matriz o el dataframe y devolver el nuevo. Esto es útil a veces, pero debe evitarse en el caso habitual, especialmente cuando su matriz es grande.

Siempre que la función esté escrita en puro R no C / C ++ / Fortran, se puede usar lo siguiente. De lo contrario, la mejor manera es depurar y usar ” saltar a “:

 > functionBody(functionName) 

También puede intentar usar print.function() , que es S3 genérico, para que la función escriba en la consola.

View([function_name]) – ej. View(mean) Asegúrese de usar mayúsculas [V]. El código de solo lectura se abrirá en el editor.