【问题标题】:which OO programming style in R will result readable to a Python programmer?R 中的哪种 OO 编程风格对 Python 程序员来说是可读的?
【发布时间】:2011-02-10 15:26:49
【问题描述】:

我是 CRAN 上 logging package 的作者,我不认为自己是一个 R 程序员,所以我尽量使它与 Python standard logging package 的代码兼容,但现在我有一个问题。我希望它能让我有机会学习更多的 R!

这是关于分层记录器的。在 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 用户会如何处理这个问题?

【问题讨论】:

  • 伙计们,我收到了两个有趣的答案,都对我的小型库增加了要求。从长远来看,我认为我更喜欢基于ReferenceClasses 的那个,但从短期来看,proto 允许我使用 R2.11...

标签: oop r coding-style


【解决方案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
> 

【讨论】:

  • 我有一个question 遵循这个答案...
  • 我认为仅将引用类用于语法糖是一个坏主意,因为它使代码更难推理。您可以通过返回函数列表来实现相同的功能。
  • @hadley 我认为这是将“记录器”的概念与引用语义而不是语法糖相结合。
  • 但是你实际上并没有修改任何东西,这使得引用语义的使用没有意义。
  • 我希望记录器正在写入(即修改)连接,例如磁盘上的文件。
【解决方案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,但是可以将每个日志对象变成一个 proto 对象,即两者都是,因为日志对象和 proto 对象都是 R 环境。这将摆脱额外的层。

请参阅http://r-proto.googlecode.com 了解更多信息。

【讨论】:

  • Gabor,我想删除distributing R package with optional dependencies 问题,但您在此处附上了一个有用的答案。如果你把它从那里移到这里,我会删除整个 dRpwod 问题。我尝试自己进行移动,但我的编辑被拒绝了。
  • 有一个删除按钮,但似乎没有删除帖子。它只问我是否要投票删除它。我已经移动了帖子,并用指向新帖子的指针替换了这个帖子。
  • 您可以编辑此答案并将其他答案的文本粘贴到此处吗?然后我将删除(投票删除)另一个整个问题。
  • 我尝试将 proto 添加到 logging 包中,但我没有管理。毕竟引用类更容易使用。
【解决方案3】:

为什么要重复这个名字?将日志对象直接传递给函数会更方便,即

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

有点像在许多函数中使用连接的方式。我猜这似乎更像是 R 的做法。

【讨论】:

  • 将记录器作为第一个参数可能更 R-ish,然后 logdebug 是记录器类的方法。
  • @Spacedman :我也会这么说,但我尽可能接近 OPs 构造。不过使用 S4 会更容易。
  • “使用 S4 会更容易” - 著名的遗言:P
  • @Hadley :好的,你让我到了那里。 :-)(我的意思是把记录器作为第一个参数会使使用 S4 更容易......或者更痛苦......)
  • 另一个问题也是基于 S4 的,但对于习惯于 Python、Java 和 C++ 的人来说更容易理解。无论如何,我正在听从你的提示,我将阅读更多关于 S4 的信息。谢谢大家!
猜你喜欢
  • 1970-01-01
  • 2017-12-03
  • 2022-06-16
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
相关资源
最近更新 更多