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

> 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。我怎样才能找到它们的源代码?


当前回答

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

> functionBody(functionName)

其他回答

对于非原语函数,R基包含一个名为body()的函数,该函数返回函数体。例如,print.Date()函数的源代码可以查看:

body(print.Date)

会产生这样的结果:

{
    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)
}

如果您正在编写脚本,并希望函数代码作为字符向量,则可以获得它。

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

会让你:

[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] "}"     

我为什么要这么做?我正在创建一个自定义S3对象(x,其中类(x) = "foo")基于一个列表。列表成员之一(名为“fun”)是一个函数,我想打印.foo()显示缩进的函数源代码。所以我最终在print.foo()中得到了以下片段:

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

它缩进并显示与x[["fun"]]相关的代码。

编辑2020-12-31

获得源代码相同字符向量的一种不那么迂回的方法是:

sourceVector = deparse(body(x$fun))

除了关于这个问题的其他答案及其副本之外,还有一种获得包函数源代码的好方法,而不需要知道它在哪个包中。 例如,如果我们想要randomForest::rfcv()的源代码:

在弹出窗口中查看/编辑:

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

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

注意,edit()打开一个文本编辑器(由用户选择),而 View()调用电子表格样式的数据查看器。

View() is great for browsing (multi-columnar) data, but usually terrible for code of anything other than toy length. so when only want to view code, edit() is IMO actually far better than View(), since with edit() you can collapse/hide/dummy out all the arg-parsing/checking/default/error-message logic which can take up to 70% of an R function, and just get to the part where the function actually operationally does something(!), what type(s) of objects its return type is, whether and how it recurses, etc.

重定向到一个单独的文件(这样你就可以在你最喜欢的IDE/编辑器/处理它的grep等):

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

视图(function_name) -例如。视图(mean)请确保使用大写[V]。只读代码将在编辑器中打开。

我不知道这是如何融入主要答案的,但它难住了我一段时间,所以我在这里添加了它:

中缀操作符

要查看一些基本中缀操作符(例如,%%,%*%,%in%)的源代码,请使用getAnywhere,例如:

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

主要的答案包括如何使用镜子来深入挖掘。

您还可以尝试使用print.function(),它是S3通用的,以便在控制台中写入该函数。