我想看看一个函数的源代码,看看它是如何工作的。我知道我可以通过在提示符处输入它的名称来打印一个函数:

> t
function (x) 
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>

在这种情况下,UseMethod(“t”)是什么意思?我如何找到实际正在使用的源代码,例如:t(1:10)?

当我看到UseMethod和当我看到standardGeneric和showMethods之间有区别吗?

> 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函数正在被调用,但我找不到这些函数的源代码。

> 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

我如何找到像.cbindts和.makeNamesTs这样的函数?

在其他情况下,有一些R代码,但大部分工作似乎是在其他地方完成的。

> 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")

我如何找到。primitive函数做什么?类似地,一些函数调用. c、. call、. fortran、. external或. internal。我怎样才能找到它们的源代码?


当前回答

PyCharm中R-plugin的快速解决方案(对于RStudio,请参阅@Arthur Yip的回答)。 如果需要,键入并在编辑器或R控制台中选择函数名。然后“转到声明”或使用快捷键CTRL-B或Command-B。 注意:这对于. primitive(即内部实现的)函数是没有用的。

其他回答

PyCharm中R-plugin的快速解决方案(对于RStudio,请参阅@Arthur Yip的回答)。 如果需要,键入并在编辑器或R控制台中选择函数名。然后“转到声明”或使用快捷键CTRL-B或Command-B。 注意:这对于. primitive(即内部实现的)函数是没有用的。

UseMethod("t")告诉您t()是一个(S3)泛型函数,它具有用于不同对象类的方法。

S3方法调度系统

对于S3类,可以使用methods函数列出特定泛型函数或类的方法。

> 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

“带星号的非可见函数”表示函数没有从其包的命名空间导出。您仍然可以通过:::函数(即stats:::t.t ts)或使用getAnywhere()查看其源代码。getAnywhere()很有用,因为您不必知道函数来自哪个包。

> 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函数的例子:

> 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.

输出已经提供了大量信息。standardGeneric是S4函数的指示器。提供了查看已定义S4方法的有用方法:

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

getMethod可以用来查看其中一个方法的源代码:

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

例如,对于每个方法,还有一些方法具有更复杂的签名

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"

要查看其中一个方法的源代码,必须提供完整的签名。

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

仅提供部分签名是不够的

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

调用未导出函数的函数

在ts.union的情况下,.cbindts和. makenamests是stats名称空间中未导出的函数。您可以使用:::operator或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
}
<bytecode: 0x38140d0>
<environment: namespace:stats>

调用已编译代码的函数

注意,“compiled”并不是指编译器包创建的字节编译的R代码。上面输出中的<bytecode: 0x294e410>行表示该函数是字节编译的,并且您仍然可以从R命令行查看源代码。

Functions that call .C, .Call, .Fortran, .External, .Internal, or .Primitive are calling entry points in compiled code, so you will have to look at sources of the compiled code if you want to fully understand the function. This GitHub mirror of the R source code is a decent place to start. The function pryr::show_c_source can be a useful tool as it will take you directly to a GitHub page for .Internal and .Primitive calls. Packages may use .C, .Call, .Fortran, and .External; but not .Internal or .Primitive, because these are used to call functions built into the R interpreter.

Calls to some of the above functions may use an object instead of a character string to reference the compiled function. In those cases, the object is of class "NativeSymbolInfo", "RegisteredNativeSymbol", or "NativeSymbol"; and printing the object yields useful information. For example, optim calls .External2(C_optimhess, res$par, fn1, gr1, con) (note that's C_optimhess, not "C_optimhess"). optim is in the stats package, so you can type stats:::C_optimhess to see information about the compiled function being called.

包中编译的代码

如果您想查看包中已编译的代码,则需要下载/解包包源代码。安装的二进制文件不够用。包的源代码可以从最初安装包的同一个CRAN(或CRAN兼容)存储库中获得。package()函数可以为您获取包的源代码。

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

这将下载Matrix包的源版本,并将相应的.tar.gz文件保存在当前目录中。编译函数的源代码可以在未压缩和未tared文件的src目录中找到。解压缩和解压缩步骤可以在R外部完成,也可以在R内部使用untar()函数完成。可以将下载和扩展步骤合并到一个调用中(注意,以这种方式一次只能下载和解包一个包):

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

或者,如果包开发是公开托管的(例如通过GitHub, R-Forge或RForge.net),你可能可以在线浏览源代码。

基本包中的编译代码

某些包被认为是“基本”包。这些包随R一起发布,它们的版本被锁定在R的版本上。示例包括base、compiler、stats和utils。因此,它们不能像上面描述的那样在CRAN上作为单独的可下载包提供。相反,它们是R源代码树的一部分,位于/src/library/下的各个包目录中。如何访问R源代码将在下一节中描述。

编译代码内置于R解释器

如果你想查看R解释器内置的代码,你需要下载/解包R源代码;或者你可以通过R Subversion存储库或Winston Chang的github镜像在线查看源代码。

Uwe Ligges的R新闻文章(PDF)(第43页)是关于如何查看. internal和. primitive函数源代码的良好参考。基本步骤是首先在src/main/names.c中查找函数名,然后在src/main/*文件中搜索“C-entry”名称。

在R编辑中有一个非常方便的函数

new_optim <- edit(optim)

它将使用R选项中指定的编辑器打开optim的源代码,然后您可以编辑它并将修改后的函数分配给new_optim。我非常喜欢这个函数来查看代码或调试代码,例如,打印一些消息或变量,甚至将它们分配给全局变量以进行进一步研究(当然你可以使用debug)。

如果您只是想查看源代码,而不希望烦人的长源代码打印在控制台上,您可以使用它

invisible(edit(optim))

显然,这不能用于查看C/ c++或Fortran源代码。

顺便说一句,edit可以打开其他对象,如列表、矩阵等,然后显示具有属性的数据结构。函数de可以用来打开一个类似excel的编辑器(如果GUI支持的话)来修改矩阵或数据帧并返回新的。这有时很方便,但在通常情况下应该避免,特别是当你的矩阵很大的时候。

在RStudio中,(至少)有3种方法:

当光标在任何功能上时,按F2键。 按住鼠标,点击函数名 Ctrl或命令 视图(function_name)(如上所述)

将打开一个带有源代码的新窗格。如果你到达。primitive或。c,你需要另一个方法,抱歉。

只要函数是用纯R而不是C/ c++ /Fortran编写的,就可以使用以下方法。否则,最好的方法是调试和使用“jump into”:

> functionBody(functionName)