How can I view the source code for a function?
我想查看一个函数的源代码,看看它是如何工作的。 我知道我可以通过在提示符下键入其名称来打印函数:
1 2 3 4 5 | > t function (x) UseMethod("t") <bytecode: 0x2332948> <environment: namespace:base> |
在这种情况下,
当我看到
1 2 3 4 5 6 7 8 9 | > with standardGeneric for"with" defined from package"base" function (data, expr, ...) standardGeneric("with") <bytecode: 0x102fb3fc0> <environment: 0x102fab988> Methods may be defined for arguments: data Use showMethods("with") for currently available ones. |
在其他情况下,我可以看到正在调用R函数,但我找不到这些函数的源代码。
1 2 3 4 5 6 7 8 9 | > ts.union function (..., dframe = FALSE) .cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE) <bytecode: 0x36fbf88> <environment: namespace:stats> > .cbindts Error: object '.cbindts' not found > .makeNamesTs Error: object '.makeNamesTs' not found |
如何找到
在其他情况下,有一些R代码,但大多数工作似乎在其他地方完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | > 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))) } <bytecode: 0x134bd10> <environment: namespace:base> > .Internal function (call) .Primitive(".Internal") > .Primitive function (name) .Primitive(".Primitive") |
我如何找出
S3方法调度系统
对于S3类,可以使用
1 2 3 4 5 6 7 8 9 10 11 12 | > 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 |
"不可见的函数带星号"表示该函数不从其包的命名空间中导出。您仍然可以通过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | > 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) } <bytecode: 0x294e410> <environment: namespace:stats> |
S4方法调度系统
S4系统是一种较新的方法调度系统,是S3系统的替代方案。以下是S4功能的示例:
1 2 3 4 5 6 7 8 9 10 11 | > library(Matrix) Loading required package: lattice > chol2inv standardGeneric for"chol2inv" defined from package"base" function (x, ...) standardGeneric("chol2inv") <bytecode: 0x000000000eafd790> <environment: 0x000000000eb06f10> Methods may be defined for arguments: x Use showMethods("chol2inv") for currently available ones. |
输出已经提供了大量信息。
1 2 3 4 5 6 7 8 | > showMethods(chol2inv) Function: chol2inv (package base) x="ANY" x="CHMfactor" x="denseMatrix" x="diagonalMatrix" x="dtrMatrix" x="sparseMatrix" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | > getMethod("chol2inv","diagonalMatrix") Method Definition: function (x, ...) { chk.s(...) tcrossprod(solve(x)) } <bytecode: 0x000000000ea2cc70> <environment: namespace:Matrix> Signatures: x target "diagonalMatrix" defined"diagonalMatrix" |
例如,对于每种方法,还存在具有更复杂签名的方法
1 2 3 4 5 6 7 8 9 10 | 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" |
要查看其中一种方法的源代码,必须提供整个签名,例如
1 | getMethod("extract" , signature = c( x ="Raster" , y ="SpatialPolygons") ) |
提供部分签名是不够的
1 2 3 | getMethod("extract",signature="SpatialPolygons") #Error in getMethod("extract", signature ="SpatialPolygons") : # No method found for function"extract" and signature SpatialPolygons |
调用未导出函数的函数
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | > 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 } <bytecode: 0x38140d0> <environment: namespace:stats> |
调用编译代码的函数
请注意,"编译"不是指由编译器包创建的字节编译的R代码。上面输出中的
调用
调用上述某些函数可能会使用对象而不是字符串来引用已编译的函数。在这些情况下,对象的类是
包中的编译代码
如果要查看包中的已编译代码,则需要下载/解压缩包源。安装的二进制文件是不够的。软件包的源代码可从最初安装软件包的相同CRAN(或CRAN兼容)存储库中获得。
1 2 3 | download.packages(pkgs ="Matrix", destdir =".", type ="source") |
这将下载Matrix包的源版本并将相应的
1 2 3 | untar(download.packages(pkgs ="Matrix", destdir =".", type ="source")[,2]) |
或者,如果包开发是公开托管的(例如通过GitHub,R-Forge或RForge.net),您可以在线浏览源代码。
基础包中的编译代码
某些包被视为"基础"包。这些软件包附带R,其版本锁定为R版本。示例包括
内置于R解释器中的编译代码
如果要查看R解释器内置的代码,则需要下载/解压缩R源代码;或者您可以通过R Subversion存储库或Winston Chang的github镜像在线查看源代码。
Uwe Ligges的R新闻文章(PDF)(p.43)是如何查看
好。
除了这个问题的其他答案及其重复之外,这里有一个很好的方法来获取包函数的源代码,而无需知道它所在的包。
例如如果我们想要
要在弹出窗口中查看/编辑它:
1 | edit(getAnywhere('rfcv'), file='source_rfcv.r') |
要重定向到单独的文件:
1 | capture.output(getAnywhere('rfcv'), file='source_rfcv.r') |
使用debug()函数进行调试时会显示它。
假设您想在t()转置函数中查看底层代码。只需输入't',就不会显示太多。
1 2 3 4 5 | >t function (x) UseMethod("t") <bytecode: 0x000000003085c010> <environment: namespace:base> |
但是,使用'debug(functionName)',它揭示了底层代码,没有内部。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | > 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) |
编辑:
debugonce()完成相同操作而不必使用undebug()
对于非原始函数,R base包含一个名为
1 | body(print.Date) |
会产生这个:
1 2 3 4 5 6 7 8 9 10 11 12 | { 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 ] ") } else print(format(x), max = max, ...) invisible(x) } |
如果您正在使用脚本并希望将函数代码作为字符向量,则可以获取它。
1 | capture.output(print(body(print.Date))) |
会得到你:
1 2 3 4 5 6 7 8 9 10 11 12 | [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 ]\ ")" [8]" }" [9]" else print(format(x), max = max, ...)" [10]" invisible(x)" [11]"}" |
我为什么要做这样的事情?我正在基于列表创建自定义S3对象(
1 2 3 | sourceVector = capture.output(print(body(x[["fun"]]))) cat(paste0(" ", sourceVector," ")) |
缩进并显示与
没有看到这是如何适应主要答案的流程但它让我困扰了一段时间所以我在这里添加它:
中缀运营商
要查看某些基本中缀运算符的源代码(例如,
1 2 3 4 5 6 7 8 | getAnywhere("%%") # A single object matching ‘%%’ was found # It was found in the following places # package:base # namespace:base # with value # # function (e1, e2) .Primitive("%%") |
主要答案包括如何使用镜子深入挖掘。
R
1 | new_optim <- edit(optim) |
它将使用R的
如果您只想查看源代码并且不希望在控制台上打印恼人的长源代码,则可以使用
1 | invisible(edit(optim)) |
显然,这不能用于查看C / C ++或Fortran源代码。
BTW,
只要该函数是用纯R而不是C / C ++ / Fortran编写的,就可以使用以下内容。否则最好的方法是调试并使用"jump into":
1 | > functionBody(functionName) |
您还可以尝试使用
在RStudio中,有(至少)3种方式:
按Ctrl或Command
将打开一个包含源代码的新窗格。如果你达到.Primitive或.C,你需要另一种方法,抱歉。