Что/Где атрибуты объекта функции?

Играя с функцией в R, я обнаружил, что в ней есть больше аспектов, чем кажется на первый взгляд.

Рассмотрим простое назначение функций, введенное непосредственно в консоли:

f <- function(x)x^2

Обычными "атрибутами" f в широком смысле являются (i) список формальных аргументов, (ii) выражение тела и (iii) среда, которая будет оболочкой рамки оценки функции, Они доступны через:

> formals(f)
$x
> body(f)
x^2
> environment(f)
<environment: R_GlobalEnv>

Кроме того, str возвращает дополнительную информацию, привязанную к f:

> str(f)
function (x)  
 - attr(*, "srcref")=Class 'srcref'  atomic [1:8] 1 6 1 19 6 19 1 1
  .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x00000000145a3cc8>

Попытайтесь связаться с ними:

> attributes(f)
$srcref
function(x)x^2

Это печатается как текст, но сохраняется как числовой вектор:

> c(attributes(f)$srcref)
[1]  1  6  1 19  6 19  1  1

И этот объект также имеет свои собственные атрибуты:

> attributes(attributes(f)$srcref)
$srcfile


$class
[1] "srcref"

Первая - это среда с тремя внутренними объектами:

> mode(attributes(attributes(f)$srcref)$srcfile)
[1] "environment"
> ls(attributes(attributes(f)$srcref)$srcfile)
[1] "filename"      "fixedNewlines" "lines" 
> attributes(attributes(f)$srcref)$srcfile$filename
[1] ""
> attributes(attributes(f)$srcref)$srcfile$fixedNewlines
[1] TRUE
> attributes(attributes(f)$srcref)$srcfile$lines
[1] "f <- function(x)x^2" ""

Вот ты! Это строка, используемая R для печати attributes(f)$srcref.

Итак, вопросы:

  • Есть ли другие объекты, связанные с f? Если да, то как их достичь?

  • Если мы разделим f его атрибутов, используя attributes(f) <- NULL, это, похоже, не влияет на функцию. Есть ли недостатки в этом?

Ответы

Ответ 1

Насколько я знаю, srcref - единственный атрибут, обычно привязанный к функциям S3. (Функции S4 - это другое дело, и я бы не рекомендовал возиться с их иногда многочисленными атрибутами).

Атрибут srcref используется для таких вещей, как включение печати комментариев, включенных в исходный код функции, и (для функций, которые были получены из файла) для установки точек останова по номеру строки, используя utils::findLineNum() и utils::setBreakpoint().

Если вы не хотите, чтобы ваши функции несли такой дополнительный багаж, вы можете отключить запись srcref, выполнив options(keep.source=FALSE). Из ?options (который также документирует соответствующий параметр keep.source.pkgs):

'keep.source: Когда "ИСТИНА", исходный код для функций (недавно      определенный или загруженный) хранится внутренне, позволяя      храниться в нужных местах. Извлечение источника путем печати     или используя 'deparse (fn, control = "useSource" ).

Для сравнения:

options(keep.source=TRUE)
f1 <- function(x) {
    ## This function is needlessly commented
    x
}

options(keep.source=FALSE)
f2 <- function(x) {
    ## This one is too
    x
}

length(attributes(f1))
# [1] 1
f1
# function(x) {
#     ## This function is needlessly commented
#     x
# }

length(attributes(f2))
# [1] 0
f2
# function (x) 
# {
#     x
# }

Ответ 2

I jst вычислил атрибут, который скомпилировал функции (package compiler), которые недоступны с attributes или str. Это bytecode.

Пример:

require(compiler)

f <- function(x){ y <- 0; for(i in 1:length(x)) y <- y + x[i]; y }

g <- cmpfun(f)

Результат:

> print(f, useSource=FALSE)
function (x) 
{
    y <- 0
    for (i in 1:length(x)) y <- y + x[i]
    y
}

> print(g, useSource=FALSE)
function (x) 
{
    y <- 0
    for (i in 1:length(x)) y <- y + x[i]
    y
}
<bytecode: 0x0000000010eb29e0>

Однако это не отображается с помощью обычных команд:

> identical(f, g)
[1] TRUE
> identical(f, g, ignore.bytecode=FALSE)
[1] FALSE
> identical(body(f), body(g), ignore.bytecode=FALSE)
[1] TRUE
> identical(attributes(f), attributes(g), ignore.bytecode=FALSE)
[1] TRUE

Кажется, он доступен только через .Internal(bodyCode(...)):

> .Internal(bodyCode(f))
{
    y <- 0
    for (i in 1:length(x)) y <- y + x[i]
    y
}

> .Internal(bodyCode(g))
<bytecode: 0x0000000010eb29e0>