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

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


当前回答

首先,尝试在没有()的情况下运行函数

示例:让我们获取cat()函数的源代码:

cat
    if (is.character(file)) 
        if (file == "") 
            file <- stdout()
        else if (startsWith(file, "|")) {
            file <- pipe(substring(file, 2L), "w")
            on.exit(close(file))
        }
        else {
            file <- file(file, ifelse(append, "a", "w"))
            on.exit(close(file))
        }
    .Internal(cat(list(...), file, sep, fill, labels, append))

但有时它会返回“UseMethod”而不是源代码

如果我们试图获取read_xml()的源代码:

library(xml2)
read_xml 
# UseMethod("read_xml")

那对我们没什么用处!在这种情况下,看看这些方法:

methods("read_xml")
# read_xml.character* read_xml.connection* read_xml.raw* read_xml.response* 

并使用getAnywhere对上面的值查看源代码:

getAnywhere("read_xml.character")

另一个例子

让我们试着看看qqnorm()的源代码:

qqnorm
# UseMethod("qqnorm") # Not very useful

methods("qqnorm")
# [1] qqnorm.default* # Making progress...

getAnywhere("qqnorm.default") # Shows source code!

其他回答

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

要查看函数的源代码,请使用print()

f <- function(x){
     x * 2
 }

print(f)

function(x){
    x * 2
}

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

对于非原语函数,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))

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

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

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