2015-05-31 15 views
5

Buduję pakiet R z klasami S4 i mam problem z funkcją new. Mam klasy o nazwie ConfigsKlasy S4: argumenty przekazane do new() nie wchodzą do ich gniazd

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

i kiedy załadować tylko tę część w moim otoczeniu globalnym, mogę stworzyć nową Configs obiekt z gniazd innych niż domyślne.

> 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 

Jednak, kiedy zainstalować cały pakiet, załadować je do świeżego środowiska i uruchomić new("Configs", features = 1000), otrzymuję features od 5. Dlaczego nie new() Wartości umieszczone w gniazdach więcej?

Mój pakiet przeszedł R CMD check bez żadnych błędów, ostrzeżeń ani notatek. Oto moje informacje o sesji.

> 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: Mam to, ale ja nadal nie jestem zadowolony.

Okaże się, że moja funkcja initialize powodowała problemy.

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

Po usunięciu, new ponownie umieszcza przedmioty w automatach. Cieszę się, że znalazłem problem, ale nie chcę całkowicie usunąć funkcji inicjowania. Chcę wygodnego sposobu wywoływania validObject i robienia innych błędów również sprawdzanie i initialize wydaje się właściwe i odpowiednie miejsce to zrobić. A jeśli odkomentuję skomentowaną linię, otrzymam nieskończoną rekursję. Jak utworzyć konstruktora bez zrywania new?

Odpowiedz

6

initialize() jest dwufunkcyjny - inicjalizacja i kopiowanie konstrukcji. Zazwyczaj lepiej (także bardziej czytelne dla użytkownika), aby zapewnić wyraźny konstruktor

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

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

validOjbect() jest wywoływana przez domyślnie zainicjować metodę podczas tworzenia obiektu obejmuje przyporządkowanie gniazd, więc nie ma potrzeby, aby nazwać to wyraźnie podczas własnego initialize metoda (patrz poniżej); Może trzeba było

.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), ...) 

z

> 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 

Ważnym zastrzeżeniem jest to, że metoda ważności jest nie zwanego gdy nie ma szczeliny inicjowane przez użytkownika, więc prototype() musi być zdefiniowana aby utworzyć poprawny obiekt (zweryfikuj to przy pomocy validObject(new("A")),

Dla twojego pytania, funkcja poprawności jest poprawnym miejscem do "sprawdzania innych błędów". Bardzo trudno jest napisać poprawny init Metoda ialize, ale coś bliżej do rozwiązania jest

.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 
}) 

Ten rodzaj dziwnej konstrukcji pozwala initialize() nadal zachowywać jako konstruktor kopii

> 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 

co jest ważne podczas dziedziczenia klas.Ale jak widać, jest to dość skomplikowane - w końcu jest naprawdę trudne i rzadko warte wysiłku, aby uzyskać poprawne initialize().

pamiętać, że nie zostały całkowicie spełnione umowę initialize(),

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

który faktycznie działa jako konstruktora kopii kiedy wywołana 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 

versus bez budowy kopiowania dla realizacji 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

Dzięki, to pomaga. Chciałem wiedzieć więcej o konstruktorach w R, nie zdając sobie z tego sprawy. – landau

Powiązane problemy