小编典典

如何查看函数的源代码?

all

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

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

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

UseMethod当我看到和当我看到standardGenericandshowMethods之间有区别with吗?

> 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. 我怎样才能找到这些的源代码?


阅读 156

收藏
2022-03-04

共1个答案

小编典典

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

调用编译代码的函数

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

调用.C, .Call, .Fortran, .External,.Internal.Primitive正在调用编译代码中的入口点的函数,因此如果您想完全理解该函数,则必须查看编译代码的源代码。这个R 源代码的 GitHub 镜像是一个不错的起点。该函数pryr::show_c_source可能是一个有用的工具,因为它会直接将您带到 GitHub 页面.Internal并进行.Primitive调用。包可以使用.C, .Call, .Fortran, 和.External; 但不是.Internalor .Primitive,因为它们用于调用内置于 R 解释器中的函数。

对上述某些函数的调用可能会使用对象而不是字符串来引用编译后的函数。在这些情况下,对象属于"NativeSymbolInfo""RegisteredNativeSymbol""NativeSymbol"; 打印对象会产生有用的信息。例如,optim调用.External2(C_optimhess, res$par, fn1, gr1, con)(注意是C_optimhess,不是"C_optimhess")。 optim位于 stats 包中,因此您可以键入stats:::C_optimhess以查看有关正在调用的已编译函数的信息。

包中的编译代码

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

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

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

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

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

基础包中的编译代码

某些软件包被视为“基本”软件包。这些软件包随 R 一起提供,并且它们的版本被锁定为 R 的版本。示例包括basecompilerstatsutils。因此,如上所述,它们不能作为 CRAN 上的单独可下载包提供。相反,它们是 R 源代码树的一部分,位于/src/library/. 下一节将介绍如何访问 R 源代码。

2022-03-04