【问题标题】:Print to R console from within function从函数内部打印到 R 控制台
【发布时间】:2018-06-07 15:54:07
【问题描述】:

我想修改 R 函数中控制台打印的行为,以恢复与全局环境中相同的行为。

就像你可以调用browser()进入函数环境并访问局部变量一样,我只是想得到表达式打印到控制台。

我们的目标是提供一种灵活、快速的方法来评估许多(数十个)表达式,以进行代码检查和理解中间输出的统计属性。我想即时执行此操作,而不必使用调试器进入函数,因为这需要额外的手动控制,也不必写出像 print("x^2"); print(x^2) 这样的冗余语句,我可能会这样做,但稍后在代码开发过程,用于更持久的代码检查。

我想到的是:编写一个函数log.to.console(),以便输出以下内容:

myfunlog = function(x){
  log.to.console()
  a1 = sqrt(x)
  a2 = exp(x)
  a1;a2;log(x);x^2
  return(a1*a2)
}
ans = myfunlog(2)
[1] a1
[1] 1.414214
[1] a2
[1] 7.389056
[1] log(x)
[1] 0.6931472
[1] x^2
[1] 4

我有一个不完全是我想要的解决方案,但是感谢 Hadley 用于表达式和范围界定的高级 R 页面,我想出了这个功能:

print.to.console = function(...){
  dots = pryr::named_dots(...)
  p = parent.frame()
  for( dot in dots){
    print(dot)
    print(eval(dot, envir = p))
  }
}

myfunprint = function(x){
  a1 = sqrt(x)
  a2 = exp(x)
  print.to.console(
    a1, a2, log(x), x^2
  )
  return(a1*a2)
}
ans = myfunprint(2)
# Which gives the output I want:
a1
[1] 1.414214
a2
[1] 7.389056
log(x)
[1] 0.6931472
x^2
[1] 4

更新:我现在可以只通过一个函数调用来显式地调用它,而之前我必须在myfunprint() 中使用environment(print.to.console) = environment()。但是,我还是想弄清楚如何实现上述log.to.console() 功能。有什么想法吗?

【问题讨论】:

  • print 函数执行此操作。我不明白存在什么问题。你能举一个print 无法向控制台输出输出的小例子吗?
  • 我希望表达式与输出一起打印,如帖子所示。这是因为在实际用例中,我们正在讨论几十个长表达式,我不想单独命名。我只想通过他们的表达调用来引用他们。我也不喜欢把 print 写两次,例如打印(“x^2”); print(x^2),所以每次我修改一个表达式我也必须修改字符串。如果我在print 中错过了这个功能,请解释一下。我仍然宁愿调用一个我可以调用一次的log.to.console() 函数,就像我调用 browser() 函数一样。谢谢
  • 如果将表达式定义为函数中的对象,则可以执行all_vars = ls(); for (i in ls) {print(i); print(get(i))} 之类的操作。这样的东西好吗?
  • 我很困惑你想要log.to.console 是什么,它与myfunlog 有什么不同(这只是一个示例函数吗?)你想要多少是动态的?打印表达式,而不仅仅是对象,真的那么重要吗?为什么不直接将 debug 参数传递给您的函数,默认为 debug = FALSE,并使用一些 if 语句来打印额外的内容,if(debug) {print.expressions.to.console()}

标签: r console cat error-checking


【解决方案1】:

我建议用字符标签和值构建一个命名列表

prtplus <- function(...){ dots <- substitute(list(...))[-1]
    anames <-  sapply(dots, deparse); setNames( list(...), anames) }

来自globalenv(),我在那里有一些杂项常量。

print( prtplus( p.lh, p.ml, p.hm) )
$p.lh
[1] 0.1

$p.ml
[1] 0.3

$p.hm
[1] 0.5

printglobalenv() 相比是多余的,但在函数中需要:

myfunlog = function(x){

   a1 = sqrt(x)
   a2 = exp(x)
   print( prtplus(
     a1, a2, log(x), x^2
   ))
   return(a1*a2)
 }

 ans = myfunlog(2)
$a1
[1] 1.414214

$a2
[1] 7.389056

$`log(x)`
[1] 0.6931472

$`x^2`
[1] 4

您也可以将print 构建成prtplus

prtplus <- function(...){ dots <- substitute(list(...))[-1]
   anames <-  sapply(dots, deparse); print(setNames( list(...), anames)) }

如果您不喜欢带有反引号名称的 R 列表的打印表示,那么这正是所要求的“外观”:

prtplus <- function(...){ dots <- substitute(list(...))[-1]
   anames <-  sapply(dots, deparse)
   vals <- setNames( list(...), anames)
   for(i in seq_along(vals)){ 
        cat( c( names(vals)[i], "\n", round( vals[[i]],6),"\n") ) }
                         }

 ans = myfunlog(2)
#----output to console---
a1 
 1.414214 
a2 
 7.389056 
log(x) 
 0.693147 
x^2 
 4 

【讨论】:

  • 这很酷,dots &lt;- substitute(list(...))[-1] 很值得了解。但这并不是我正在寻找的完整答案......
  • 添加了带有cat的循环显示。
  • 酷,我们都有一个解决方案,可以很好地包装表达式和打印。我更多地谈论第一个(主要)问题:有没有一种方法可以通过在感兴趣的函数体内添加对某些log.to.console() 函数的调用来输出表达式。我知道这是一个更难的问题……但并非不可能?
  • 我认为您可能需要修改 parseeval 的行为,以便每个表达式都回显到控制台。 (这远高于我的工资等级。)您可能想看看trace 功能是如何运作的。
  • 转念一想,真正需要的是对 &lt;- 的本地重新定义(这只是一个带有两个参数的函数)。我尝试将函数重新分配给&lt;-,令我惊讶的是,口译员没有抱怨。 (但后来 R 没有做任何有用的事情,所以显然我现在可以保留所有的部分。)
【解决方案2】:

要强制打印命令打印到控制台,只需使用: print(con=stdout(), "我的文字")

注意: 如果您之前在前面的语句中指定了连接“con”,例如 readLines(con="inputfile"),那么这也会为下一个打印语句设置输出连接,如果您不调用,您最终会覆盖您的输入文件con=stdout() 在您的打印语句中。似乎 R 为任何下一个输入/输出语句保存了连接“con”的任何规范。

【讨论】:

    猜你喜欢
    • 2012-06-06
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多