Какой стиль программирования OO в R будет доступен для чтения программисту Python?

Я являюсь автором logging package на CRAN, я не считаю себя программистом R, поэтому я попытался сделать его совместимым с кодами стандартный пакет протоколов Python, но теперь У меня есть вопрос. и я надеюсь, что это даст мне шанс узнать еще больше!!

об иерархических регистраторах. в Python я бы создал регистратор и отправил записи регистрации:

l = logging.getLogger("some.lower.name")
l.debug("test")
l.info("some")
l.warn("say no")

В моем R-пакете вместо этого вы не создаете регистратор, на который вы отправляете сообщения, вы вызываете функцию, где одним из аргументов является имя регистратора. что-то вроде

logdebug("test", logger="some.lower.name")
loginfo("some", logger="some.lower.name")
logwarn("say no", logger="some.lower.name")

проблема в том, что вам нужно повторять имя регистратора каждый раз, когда вы хотите отправить ему сообщение регистрации. Я думал, я мог бы создать частично примененный объект функции и вызывать это вместо чего-то вроде

logdebug <- curry(logging::logdebug, logger="some.lower.logger")

но тогда мне нужно сделать это для всех функций отладки...

как вы подходите к этим пользователям R?

Ответ 1

Звучит как задание для ссылочного класса ?setRefClass, ?ReferenceClasses

Logger <- setRefClass("Logger",
                  fields=list(name = "character"),
                  methods=list(
                    log = function(level, ...) 
                          { levellog(level, ..., logger=name) },
                    debug = function(...) { log("DEBUG", ...) },
                    info = function(...) { log("INFO", ...) },
                    warn = function(...) { log("WARN", ...) },
                    error = function(...) { log("ERROR", ...) }
                    ))

а затем

> basicConfig()
> l <- Logger$new(name="hierarchic.logger.name")
> l$debug("oops")
> l$info("oops")
2011-02-11 11:54:05 NumericLevel(INFO):hierarchic.logger.name:oops
> l$warn("oops")
2011-02-11 11:54:11 NumericLevel(WARN):hierarchic.logger.name:oops
> 

Ответ 2

Это можно сделать с помощью пакета proto. Это поддерживает более старые версии R (в течение многих лет), поэтому у вас не было бы проблемы с старыми и новыми версиями R.

library(proto)
library(logging)

Logger. <- proto(
        new = function(this, name)
            this$proto(name = name),
        log = function(this, ...) 
            levellog(..., logger = this$name),
        setLevel = function(this, newLevel) 
            logging::setLevel(newLevel, container = this$name),
        addHandler = function(this, ...)
            logging::addHandler(this, ..., logger = this$name), 
        warn = function(this, ...)
            this$log(loglevels["WARN"], ...),
        error = function(this, ...)
            this$log(loglevels["ERROR"], ...) 
)
basicConfig()
l <- Logger.$new(name = "hierarchic.logger.name")
l$warn("this may be bad")
l$error("this definitely is bad")

Это дает результат:

> basicConfig()
> l <- Logger.$new(name = "hierarchic.logger.name")
> l$warn("this may be bad")
2011-02-28 10:17:54 WARNING:hierarchic.logger.name:this may be bad
> l$error("this definitely is bad")
2011-02-28 10:17:54 ERROR:hierarchic.logger.name:this definitely is bad

В вышесказанном мы просто проложили proto поверх регистрации, но можно было бы превратить каждый объект регистрации в прото-объект, т.е. это было бы одновременно, поскольку оба объекта ведения журнала и прото-объекты были средами R. Это избавит вас от дополнительного слоя.

Подробнее см. http://r-proto.googlecode.com.

Ответ 3

Зачем вам повторять имя? Было бы удобнее передать лог-объект непосредственно функции, т.е.

logdebug("test",logger=l)
# or
logdebug("test",l)

Похоже, что можно использовать соединения в нескольких функциях. Похоже, это похоже на то, как я это делаю.