【问题标题】:Unused arguments in RR中未使用的参数
【发布时间】:2012-05-03 11:10:33
【问题描述】:

R 中,是否可以让软件忽略在运行模块时定义了未使用的参数这一事实?

例如,我有一个模块multiply(a,b),它返回ab 的乘积。如果我这样调用模块,我会收到一个错误:

multiply(a=20,b=30,c=10)

返回错误似乎有点不必要,因为已指定所需的输入 ab。是否有可能避免这种不良行为?

一个简单的解决方案就是停止指定c,但这并不能解释为什么R 会这样。有没有其他方法可以解决这个问题?

【问题讨论】:

  • 针对“返回错误似乎有点不必要”,我不认为这是不必要的,因为您显然期望分配额外的参数,您需要被告知不存在参数来防止函数的“意外行为”。
  • 首先,它是一个函数而不是一个模块。其次,您的函数如何知道如何处理附加参数?我认为答案是正确的,但它应该更能说明人们如何实际使用点(又名“...”)。

标签: r


【解决方案1】:

更改乘法的定义以获取额外的未知参数:

multiply <- function(a, b, ...) {
  # Original code
}

【讨论】:

    【解决方案2】:

    R.utils 包有一个叫做 doCall 的函数,它类似于 do.call,但如果传递了未使用的参数,它不会返回错误。

    multiply <- function(a, b) a * b
    
    # these will fail
    multiply(a = 20, b = 30, c = 10)
    # Error in multiply(a = 20, b = 30, c = 10) : unused argument (c = 10)
    do.call(multiply, list(a = 20, b = 30, c = 10))
    # Error in (function (a, b)  : unused argument (c = 10)
    
    # R.utils::doCall will work
    R.utils::doCall(multiply, args = list(a = 20, b = 30, c = 10))
    # [1] 600
    # it also does not require the arguments to be passed as a list
    R.utils::doCall(multiply, a = 20, b = 30, c = 10)
    # [1] 600
    

    【讨论】:

      【解决方案3】:

      一种方法(我无法想象这是良好的编程习惯)是添加 ...,它传统上用于将一个函数中指定的参数传递给另一个函数。

      > multiply <- function(a,b) a*b
      > multiply(a = 2,b = 4,c = 8)
      Error in multiply(a = 2, b = 4, c = 8) : unused argument(s) (c = 8)
      > multiply2 <- function(a,b,...) a*b
      > multiply2(a = 2,b = 4,c = 8)
      [1] 8
      

      您可以阅读更多关于... 旨在用于here

      【讨论】:

      • 您为什么认为这是不好的做法? (不是不​​同意,只是好奇。)我觉得我已经阅读了很多 R 文档,其中 ... 参数被简单地忽略了,这表明人们不时这样做。
      • ... 旨在传递给子函数,特别是方法,其中所需(或接受)的参数列表在编写函数时是未知的。如果您确实将 ... 向下传递,您将在更深层次上得到“未使用的参数”错误。一般来说,不知道你是否在使用参数会导致混淆。
      • 我突然想到,我经常用 C++ 虚拟方法来做这件事。参数列表当然是固定的,但是有些对象方法不需要所有的参数。
      • @joran - 老实说,并没有考虑太多 其他函数,并且那个未使用的参数现在用于某些事情。您是对的,尽管一些 R 文档确实具有 ... is ignored for now 的效果,所以也许我想多了。
      【解决方案4】:

      您可以在函数定义中使用点:...

      myfun <- function(a, b, ...){
        cat(a,b)
      }
      
      myfun(a=4,b=7,hello=3)
      
      # 4 7
      

      【讨论】:

        【解决方案5】:

        我和你有同样的问题。我有一长串论据,其中大部分是无关紧要的。我不想硬编码它们。这就是我想出的

        library(magrittr)
        do_func_ignore_things <- function(data, what){
            acceptable_args <- data[names(data) %in% (formals(what) %>% names)]
            do.call(what, acceptable_args %>% as.list)
        }
        
        do_func_ignore_things(c(n = 3, hello = 12, mean = -10), "rnorm")
        # -9.230675 -10.503509 -10.927077
        

        【讨论】:

          【解决方案6】:

          R 有一个函数 prod() 可以很好地进行乘法运算。提问者给出的示例在 prod() 函数中运行良好,不会返回错误。`

          prod(a=20,b=30,c=10)
          
           # 6000
          

          在任何情况下,突出显示的错误都是纠正它的机会,所以不是坏行为。

          【讨论】:

          • 没错,但我认为他们只是将乘法函数用作一个简单的例子,而不是因为他们特别需要一种方法来将数字相乘
          【解决方案7】:

          由于已经有许多答案直接解决了这个问题,而且 R 经常被技术熟练的非程序员使用,所以让我快速概述错误存在的原因,并建议不要使用抑制解决方法。

          参数的数量是定义函数的一个重要方面。如果参数的数量不匹配,这很好地表明调用者的意图与函数将要执行的操作之间存在不匹配。出于这个原因,这将是许多编程语言中的编译错误,包括 Java、Python、Haskell 和许多其他语言。事实上,如果类型不匹配,许多这些语言中更严格的类型检查也会导致错误。

          随着程序规模的增长和代码的老化,越来越难以发现这种不匹配是故意的还是真正的错误。这就是为什么“干净代码”的想法——简单易读的代码,没有错误或警告——通常是专业程序员的标准工作。

          因此,我建议重新编写代码以删除不必要的参数。将来为自己和他人理解和调试会更简单。

          当然,我知道 R 用户经常使用生命周期有限的小脚本,大型软件工程项目的通常权衡并不总是适用。也许对于您的快速脚本,它只会使用一周,只是抑制错误是有意义的。然而,人们普遍观察到(我在自己的经验中已经看到),在撰写本文时,代码的持久性很少是显而易见的。如果您正在追求开放科学,并发布您的代码和数据,那么该代码在未来对其他人有用,这样他们就可以重现您的结果。

          【讨论】:

            猜你喜欢
            • 2020-03-14
            • 2015-10-01
            • 1970-01-01
            • 2017-04-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多