Как я могу просмотреть исходный код функции?
Я хочу посмотреть на исходный код функции, чтобы увидеть, как она работает. Я знаю, что могу напечатать функцию, набрав ее имя в командной строке:
> t
function (x)
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>
В этом случае, что делает UseMethod("t")
имею в виду? Как мне найти исходный код, который фактически используется, например: t(1:10)
?
Есть ли разница между тем, когда я вижу UseMethod
и когда я вижу standardGeneric
а также showMethods
как с 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
, Как я могу найти исходный код для тех?
13 ответов
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
Вызываете точки входа в скомпилированном коде, поэтому вам нужно будет взглянуть на источники скомпилированного кода, если вы хотите полностью понять функцию. Это зеркало GitHub исходного кода R - хорошее место для начала. Функция pryr::show_c_source
может быть полезным инструментом, так как он приведет вас прямо на страницу GitHub для .Internal
а также .Primitive
звонки. Пакеты могут использовать .C
, .Call
, .Fortran
, а также .External
; но нет .Internal
или же .Primitive
потому что они используются для вызова функций, встроенных в интерпретатор R.
При вызовах некоторых из вышеуказанных функций может использоваться объект вместо строки символов для ссылки на скомпилированную функцию. В этих случаях объект имеет класс "NativeSymbolInfo"
, "RegisteredNativeSymbol"
, или же "NativeSymbol"
; и печать объекта дает полезную информацию. Например, optim
звонки .External2(C_optimhess, res$par, fn1, gr1, con)
(обратите внимание, что это C_optimhess
не "C_optimhess"
). optim
находится в пакете статистики, так что вы можете ввести stats:::C_optimhess
чтобы увидеть информацию о вызываемой скомпилированной функции.
Скомпилированный код в пакете
Если вы хотите просмотреть скомпилированный код в пакете, вам необходимо скачать / распаковать исходный код пакета. Установленных двоичных файлов недостаточно. Исходный код пакета доступен из того же хранилища CRAN (или CRAN-совместимого), из которого пакет был первоначально установлен. download.packages()
Функция может получить источник пакета для вас.
download.packages(pkgs = "Matrix",
destdir = ".",
type = "source")
Это загрузит исходную версию пакета Matrix и сохранит соответствующую .tar.gz
файл в текущем каталоге. Исходный код для скомпилированных функций можно найти в 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 или зеркало github Уинстона Чанга.
Новостная статья Уве Лиггеса R (PDF) (стр. 43) является хорошим общим справочным материалом о том, как просматривать исходный код для .Internal
а также .Primitive
функции. Основные шаги - сначала найти имя функции в src/main/names.c
а затем найдите "C-запись" имя в файлах в src/main/*
,
В дополнение к другим ответам на этот вопрос и его дубликатам, есть хороший способ получить исходный код для функции пакета без необходимости знать, в каком пакете он находится. Например, если нам нужен источник для randomForest::rfcv()
:
Чтобы просмотреть / отредактировать его во всплывающем окне:
edit(getAnywhere('rfcv'), file='source_rfcv.r')
Чтобы перенаправить в отдельный файл:
capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
Для не примитивных функций, R base включает функцию, называемую 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
, где class(x) = "foo"
) на основе списка. Один из членов списка (названный "fun") был функцией, и я хотел print.foo()
для отображения исходного кода функции, с отступом. Итак, я закончил со следующим фрагментом в print.foo()
:
sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0(" ", sourceVector, "\n"))
который отступает и отображает код, связанный с x[["fun"]]
,
Это раскрывается при отладке с использованием функции debug (). Предположим, вы хотите увидеть базовый код в функции транспонирования t (). Просто набрав 't', мало что видно.
>t
function (x)
UseMethod("t")
<bytecode: 0x000000003085c010>
<environment: namespace:base>
Но, используя 'debug (functionName)', он раскрывает лежащий в основе код, без внутренних данных.
> debug(t)
> t(co2)
debugging in: t(co2)
debug: UseMethod("t")
Browse[2]>
debugging in: t.ts(co2)
debug: {
cl <- oldClass(x)
other <- !(cl %in% c("ts", "mts"))
class(x) <- if (any(other))
cl[other]
attr(x, "tsp") <- NULL
t(x)
}
Browse[3]>
debug: cl <- oldClass(x)
Browse[3]>
debug: other <- !(cl %in% c("ts", "mts"))
Browse[3]>
debug: class(x) <- if (any(other)) cl[other]
Browse[3]>
debug: attr(x, "tsp") <- NULL
Browse[3]>
debug: t(x)
РЕДАКТИРОВАТЬ: debugonce () выполняет то же самое без использования undebug ()
Не видел, как это вписалось в поток основного ответа, но это меня немного озадачило, поэтому я добавляю его сюда:
Инфиксные операторы
Чтобы увидеть исходный код некоторых базовых инфиксных операторов (например, %%
, %*%
, %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("%%")
Основной ответ охватывает, как затем использовать зеркала, чтобы копать глубже.
В RStudio нажмите клавишу F2, когда курсор находится на любой функции. Откроется новая панель с источником. Тем не менее, вам придется искать в другом месте, если вы достигнете.Primitive, .C
В R есть очень удобная функция edit
new_optim <- edit(optim)
Откроется исходный код optim
используя редактор, указанный в R options
, а затем вы можете отредактировать его и назначить измененную функцию new_optim
, Мне очень нравится эта функция, чтобы просматривать код или отлаживать код, например, печатать некоторые сообщения или переменные или даже назначать их глобальным переменным для дальнейшего исследования (конечно, вы можете использовать debug
).
Если вы просто хотите просмотреть исходный код и не хотите, чтобы раздражающий длинный исходный код печатался на вашей консоли, вы можете использовать
invisible(edit(optim))
Ясно, что это нельзя использовать для просмотра исходного кода на C/C++ или Fortran.
КСТАТИ, edit
может открывать другие объекты, такие как список, матрица и т. д., которые затем отображают структуру данных с атрибутами. функция de
Может использоваться для открытия редактора, подобного Excel (если GUI поддерживает его), для изменения матрицы или фрейма данных и возврата нового. Иногда это удобно, но в обычном случае этого следует избегать, особенно когда матрица большая.
Пока функция написана на чистом R, а не на C/C++/Fortran, можно использовать следующее. В противном случае лучший способ - это отладка и использование "перехода в":
> functionBody(functionName)
View([function_name])
Например View(mean)
Обязательно используйте прописные буквы [V]. Код только для чтения откроется в редакторе.
Вы также можете попробовать использовать print.function()
, который является общим S3, чтобы получить функцию записи в консоли.
Чтобы увидеть исходный код функции, используйте print()
f <- function(x){
x * 2
}
print(f)
function(x){
x * 2
}
Во-первых, попробуйте запустить функцию без
()
Пример: давайте получим исходный код для
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-плагина в PyCharm (для RStudio см. ответ @Arthur Yip). Введите, если необходимо, и выберите имя функции в редакторе или консоли R. Затем «Перейти к декларации» или используйте сочетания клавиш CTRL-B или Command-B. Примечание: это не полезно для.Primitive
(т.е. внутренне реализованные) функции.