2013-04-09 9 views
16

Grając z funkcją w R, odkryłem, że jest w niej więcej aspektów niż to, co widać na pierwszy rzut oka.Co/gdzie są atrybuty obiektu funkcji?

Rozważmy THS proste przypisanie funkcji, wpisane bezpośrednio w konsoli:

f <- function(x)x^2 

Zwykła „atrybuty” od f, w szerokim tego słowa znaczeniu, to: (i) wykaz formalnych argumentów, (ii) ekspresji ciała i (iii) środowiska, które będzie obudową ramki oceny funkcji. Są one dostępne za pośrednictwem:

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

Ponadto str powraca Więcej informacji dołączony do 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> 

Spróbujmy je osiągnąć:

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

To jest drukowane jako tekst, ale jest przechowywany jako wektor liczbowy:

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

I to obiekt posiada również własne atrybuty:

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


$class 
[1] "srcref" 

Pierwszy z nich to środowisko, z 3 wewnętrznych obiektów:

> 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" "" 

Tu jesteś! Jest to ciąg używany przez R do drukowania attributes(f)$srcref.

więc pytania są:

  1. Czy są jakieś inneobiekty związane f? Jeśli tak, jak do nich dotrzeć?

  2. Jeśli usuniemy f z jego atrybutów, używając attributes(f) <- NULL, nie ma to wpływu na funkcję. Czy są jakieś wady tego działania?

+0

Jestem bardzo sceptyczny wobec twojego roszczenia nr 2. O ile nie pokonałeś wypieku z pozbawionej funkcji, w tym pośrednich wywołań środowiskowych, modyfikując jego elementy "ciała", a raczej o wielu rzeczach, o których nie wiem, możesz uspokoić to stwierdzenie. –

+0

@CarlWitthoft, Próbowałem użyć 'attributes (f) <- NULL' z funkcją, która ma środowisko inne niż' R_GlobalEnv' (i faktycznie szuka symbolu w swojej obudowie) i nadal działa. Ponadto użycie 'body <-' automatycznie usuwa funkcję z jej atrybutów. Biorąc pod uwagę odpowiedź Josha poniżej, istnieje nawet opcja, aby te atrybuty pozostawały puste od samego początku. Czy możesz zaproponować kolejny test, w którym potrzebne są atrybuty? –

Odpowiedz

13

Z tego co wiem, srcref jest jedynym atrybutem zwykle dołączonym do funkcji S3. (Funkcje S4 to inna sprawa i nie polecałabym mieszania się z ich czasami licznymi atrybutami).

Atrybut srcref służy do rzeczy jak umożliwiając drukowanie uwag zawartych w kodzie źródłowym funkcji, a (dla funkcji, które zostały pozyskane z pliku) do ustawiania punktów przerwań przez numer linii, używając utils::findLineNum() i utils::setBreakpoint().

Jeśli nie chcesz, aby Twoje funkcje przewoziły dodatkowy bagaż, możesz wyłączyć nagrywanie srcref, wykonując options(keep.source=FALSE). Od ?options (która dokumentuje również związane keep.source.pkgs opcję):

„keep.source”: Kiedy „prawdziwy”, kod źródłowy funkcji (nowo zdefiniowane lub załadowane) przechowywana jest wewnętrznie dzięki czemu komentarze do być przechowywane w odpowiednich miejscach.Pobierz źródło, drukując lub używając "deparse (fn, control =" useSource ")".

Porównaj:

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 
# } 
+0

Bardzo interesujące. Wydaje się, że 'print' używa' body' funkcji, gdy nie ma atrybutu 'srcref'. –

+0

@ Ferdinand.kraft - Dobra uwaga. Sprawdź 'print.function (f1)' vs. 'print.function (f1, useSource = FALSE)'. –

3

I JST zorientowali się, że atrybut skompilowane funkcje (pakiet compiler) mają, że nie jest dostępna z attributes lub str. To jest bytecode.

Przykład:

require(compiler) 

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

g <- cmpfun(f) 

Wynikiem jest:

> 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> 

to jednak nie wykazuje przy normalnych poleceń:

> 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 

To wydaje się być dostępne jedynie poprzez .Internal(bodyCode(...)) :

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

> .Internal(bodyCode(g)) 
<bytecode: 0x0000000010eb29e0> 
Powiązane problemy