2015-05-31 15 views
5

Sto costruendo un pacchetto R con classi S4 e ho problemi con la funzione new. Ho una classe denominata ConfigsClassi S4: gli argomenti passati a new() non vanno nei loro slot

setClass("Configs", 
    slots = list(
    burnin = "numeric", 
    chains = "numeric", 
    features = "numeric", 
    iterations = "numeric", 
    mphtol = "numeric", 
    samples = "numeric", 
    seed = "numeric", 
    thin = "numeric", 
    verbose = "numeric" 
), 
    prototype = list(
    burnin = 0, 
    chains = 2, 
    features = 5, 
    iterations = 5, 
    mphtol = 1e-4, 
    samples = 3, 
    seed = sample(1e6, 1), 
    thin = 0, 
    verbose = 0 
) 
) 

e quando carico proprio questa parte nel mio ambiente globale, posso creare un nuovo oggetto con Configs slot diversi da quelli predefiniti.

> new("Configs", features = 1000) 
An object of class "Configs" 
Slot "burnin": 
[1] 0 

Slot "chains": 
[1] 2 

Slot "features": 
[1] 1000 

Slot "iterations": 
[1] 5 

Slot "mphtol": 
[1] 1e-04 

Slot "samples": 
[1] 3 

Slot "seed": 
[1] 437211 

Slot "thin": 
[1] 0 

Slot "verbose": 
[1] 0 

Tuttavia, quando installo l'intero pacchetto, caricarlo in un ambiente fresco, e correre new("Configs", features = 1000), ho un features di 5. Perché non new() valori messi in slot più?

Il mio pacco ha superato R CMD check senza errori, avvisi o note. Ecco le mie informazioni sulla sessione.

> sessionInfo() 
R version 3.2.0 (2015-04-16) 
Platform: x86_64-unknown-linux-gnu (64-bit) 
Running under: CentOS release 6.6 (Final) 

locale: 
[1] LC_CTYPE=en_US.UTF-8  LC_NUMERIC=C    
[3] LC_TIME=en_US.UTF-8  LC_COLLATE=en_US.UTF-8  
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 
[7] LC_PAPER=en_US.UTF-8  LC_NAME=C     
[9] LC_ADDRESS=C    LC_TELEPHONE=C    
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] heterosis_0.0 pracma_1.8.3 MCMCpack_1.3-3 MASS_7.3-40 coda_0.17-1 

loaded via a namespace (and not attached): 
[1] tools_3.2.0  grid_3.2.0  lattice_0.20-31 

Edit: Ho capito, ma non sono ancora soddisfatto.

Si scopre che la mia funzione initialize stava causando problemi.

setMethod("initialize", "Configs", function(.Object, ...){ 
# .Object = new("Configs", ...) 
    validObject(.Object)  
    return(.Object) 
}) 

Quando lo rimuovo, new inserisce nuovamente gli oggetti negli slot. Sono contento di aver trovato il problema, ma non voglio rimuovere completamente la mia funzione di inizializzazione. Voglio un modo conveniente per chiamare validObject e fare anche un altro controllo degli errori, e initialize sembra un posto adeguato e appropriato per farlo. E se disapprovo la riga commentata, ottengo una ricorsione infinita. Come posso creare un costruttore senza interrompere new?

risposta

6

initialize() è dual-purpose - inizializzazione e copia costruzione. Di solito è meglio (anche più informativo per l'utente) per fornire un costruttore esplicito

.A = setClass("A", representation(x="numeric")) 

A = function(x=numeric(), ...) 
    .A(x=x, ...) 

validOjbect() viene chiamato dal difetto metodo quando la creazione di oggetti comporta l'assegnazione di slot inizializzare, quindi non c'è bisogno di chiamare in modo esplicito durante il proprio inizializzazione metodo (vedi sotto); forse avresti

.A = setClass("A", representation(x="numeric"), 
    prototype=prototype(x=NA_integer_)) 

setValidity("A", function(object) { 
    if (length([email protected]) != 1L) 
     "'x' must be length 1" 
    else TRUE 
}) 

A = function(x=NA_integer_, ...) 
    ## signature is informative -- 'x' is integer(1), not just '...' 
    ## coercion (e.g., as.integer(), below) and other set-up 
    new("A", x=as.integer(x), ...) 

con

> A() 
An object of class "A" 
Slot "x": 
[1] NA 

> A(x=1) 
An object of class "A" 
Slot "x": 
[1] 1 

> A(x=1:2) 
Error in validObject(.Object) : 
    invalid class "A" object: 'x' must be length 1 

Un avvertimento importante è che il metodo di validità è non chiamati quando non ci sono fessure inizializzati dall'utente, in modo che il prototype() deve essere definita per creare un oggetto valido (verificare questo con validObject(new("A")).

Per la tua domanda, la funzione di validità è il posto giusto per fare 'altri errori di controllo'. È molto difficile scrivere un init corretto Metodo ialize, ma qualcosa di più vicino a correggere è

.B = setClass("B", 
    representation(x="numeric", y="numeric"), 
    prototype=prototype(x=NA_integer_, y=NA_real_)) 
setMethod("initialize", "B", 
    function(.Object, ..., [email protected], [email protected]) 
{ 
    ## pre-processing, then invoke 'next' initialize() method 
    ## base initialize() creates the object then calls validObject() 
    ## so no need for explicit test of validity 
    .Object <- callNextMethod(.Object, ..., x=x, y=y) 
    ## post-processing 
    .Object 
}) 

Questo tipo di costruzione permette strano initialize() di continuare a comportarsi come un costruttore di copia

> b = new("B", x=1, y=2) # constructor 
> initialize(b, x=2)  # copy-constructor 
An object of class "B" 
Slot "x": 
[1] 2 

Slot "y": 
[1] 2 

che è importante durante le lezioni eredità.Ma come puoi vedere, questo è abbastanza complicato - alla fine è davvero difficile e raramente vale la pena di correggere initialize() corretto.

Nota che non abbiamo completamente adempiuto il contratto di initialize(),

setClass("C", representation(x="numeric", y="numeric")) # default initialize() 

che agisce in realtà come costruttore di copia quando viene chiamato con new()

> c = new("C", x=1, y=2) 
> new("C", c, x=2) 
An object of class "C" 
Slot "x": 
[1] 2 

Slot "y": 
[1] 2 

contro alcuna copia costruzione per l'attuazione

di B
> b = new("B", x=1, y=2) 
> new("B", b, x=2) 
An object of class "B" 
Slot "x": 
[1] 2 

Slot "y": 
[1] NA 
+0

Grazie, questo aiuta. In realtà volevo saperne di più sui costruttori in R senza rendermene conto. – landau

Problemi correlati