S4 отсутствует или NULL аргументы для методов? - PullRequest
6 голосов
/ 14 декабря 2010

Есть ли способ определить, что происходит, когда аргумент метода отсутствует или равен NULL ?

В приведенном ниже примере я хотел бы вызывать одну и ту же функцию независимо от того, набираю ли я foo() или foo(NULL). Конечно, я знаю, что у меня может быть метод setMethod("foo","NULL",function(x) foo()), но это репликация кода и возможный источник ошибок.

Спасибо!

setGeneric("foo",function(x) standardGeneric("foo"))
setMethod("foo","numeric",function(x) "numeric")
setMethod("foo","NULL",function(x) "NULL")
setMethod("foo","missing",function(x) "missing")

R> foo(1)
[1] "numeric"
R> foo()
[1] "missing"
R> foo(NULL)
[1] "NULL"

Ответы [ 3 ]

12 голосов
/ 14 декабря 2013

Почти ровно на три года позже, но вы действительно хотите, чтобы setClassUnion:

> setClassUnion("missingOrNULL", c("missing", "NULL"))
> setGeneric("foo",function(x) standardGeneric("foo"))
> setMethod("foo","numeric",function(x) "numeric")
> setMethod("foo","missingOrNULL",function(x) "NULL")

> foo(1)
[1] "numeric"
> foo()
[1] "NULL"
> foo(NULL)
[1] "NULL"

setClassUnion создал виртуальный класс, который является суперклассом (родительским) для классов компонентов, поэтомуоба потомка наследуются от этого класса, что означает, что вы можете отправлять одну и ту же функцию каждому потомку.

3 голосов
/ 14 декабря 2010

Использование setMethod("foo","NULL",function(x) foo()) не является репликацией кода, так как вы не копируете код, а вызываете его. Я бы сказал, что это очень хороший способ решения вашей проблемы.

2 голосов
/ 15 декабря 2010

Полагаю, что правильным способом является использование «ЛЮБОГО» в подписи:

setGeneric("foo",function(x) standardGeneric("foo"))
setMethod("foo","numeric",function(x) "numeric")
setMethod("foo","ANY",function(x) "ANY")

> foo(1)
[1] "numeric"

> foo()
[1] "ANY"

> foo(NULL)
[1] "ANY"

Убедитесь, что вы указали любую другую возможность, о которой вы хотите позаботиться, поскольку «ЛЮБОЙ» также берет все остальныеэто не соответствует сигнатуре другого метода.

Если у вас есть аргументы, которые могут отсутствовать, вы можете просто не указывать их в сигнатуре setMethods и установить стандартное значение по умолчанию.Это, по моему скромному мнению, лучший выбор дизайна.

setGeneric("foo",function(x,y=NULL,...) {
        standardGeneric("foo")
    })

setMethod("foo",c("numeric","ANY"),function(x,y,...) {
            print(y)
    })
setMethod("foo",c("numeric","numeric"),function(x,y,...) {
            x + y
    })

> foo(1)
NULL

> foo(1,3)
[1] 4

> foo(1,NULL)
NULL

Теперь вы можете работать с NULL-кодами в коде так же, как и с отсутствующими аргументами.

О sidenote: Теперь я добавил NULL в качестве значения по умолчанию, но во многих случаях есть гораздо более разумный выбор для значений по умолчанию.Просто помните, что setMethod принимает начальную сигнатуру, и что когда y установлен как NULL, он не заменяется значением по умолчанию.

Например:

setGeneric("bar",function(x,y=2,...) {
        standardGeneric("bar")
    })

setMethod("bar",c("numeric","ANY"),function(x,y,...) {
            x + y
    })
setMethod("bar",c("numeric","numeric"),function(x,y,...) {
            x - y
    })

> bar(1)
[1] 3

> bar(1,2)
[1] -1

> bar(1,NULL) # this y is not replaced with the default!
numeric(0)

DIRTY HACK:

Я нахожу подход немного неловким, но вот грязный хак, который устанавливает все недостающие параметры в NULL:

setGeneric("foo",function(x,y,z) {
    pars <- names(formals(foo))
    for(i in pars){
        tryerr <- try(get(i),silent=T)
        if(is(tryerr,"try-error")){ assign(i,NULL)}
    }
    standardGeneric("foo")
}

Попробовав это, вы получите:

> foo(1)
[1] "numeric"

> foo(NULL)
[1] "NULL"

> foo()
[1] "NULL"

Так что вы никогда больше не отправляетесь к пропавшим без вести.Вы можете просто забыть об этом.Но это не правильный способ делать вещи ...

...