我想看看一个函数的源代码,看看它是如何工作的。我知道我可以通过在提示符处输入它的名称来打印一个函数:
> 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!
对于非原语函数,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))