【问题标题】:Get all Parameters as List获取所有参数作为列表
【发布时间】:2012-08-06 18:49:24
【问题描述】:

R 是否提供对象/函数/方法/关键字来获取所有函数参数?

举个例子: function(a, b="default", ...) 将在函数环境中提供ab 以及...。是否有类似于list(...) 的语句也会在结果中包含ab

或者换一种说法:list(a=a, b=b, ...) 的简写,给定function(a, b, ...)

【问题讨论】:

  • 这个问题的问题是,不清楚你在问什么。您是在问如何获取 1) 调用函数的 values; 2) 调用函数的表达式; 3) 函数定义中的默认值?您的问题根本不清楚,因此您对所有这 3 个选项都有 3 种不同类型的答案。

标签: r


【解决方案1】:

一种解决方案是使用:

tempf <- function(a, b = 2, ...) {
    argg <- c(as.list(environment()), list(...))
    print(argg)
}
tempf(1, c = 3)
$a
[1] 1

$b
[1] 2

$c
[1] 3

这将创建参数值的命名列表。

【讨论】:

  • 你知道有一个包会导出这样的函数(只有...作为参数)吗?
  • 或者简单地 print(as.list(environment())) 如果你没有 ... 作为参数
  • 这很好用,与公认的答案相比,它的优势在于它捕获传递给函数的 values,而不是可以捕获的 expressions用于计算值。如果您尝试保存 args 以便稍后调用该函数,您可能需要这些值。
  • 值得指出的是,通过在函数的最开始运行argg &lt;- c(as.list(environment()), list(...)) 来“捕获”参数通常很重要。否则,environment() 最终将包含在 tempf() 中创建的其他变量
【解决方案2】:

我想你想要match.call:

tmpfun <- function(a,b,...) {
print(as.list(match.call()))
print(as.list(match.call(expand.dots=FALSE)))
}
> tmpfun(a=1, b=2, c=3, d=4)
[[1]]
tmpfun

$a
[1] 1

$b
[1] 2

$c
[1] 3

$d
[1] 4

[[1]]
tmpfun

$a
[1] 1

$b
[1] 2

$...
$...$c
[1] 3

$...$d
[1] 4

【讨论】:

  • 如果在函数调用中没有覆盖默认值,这将失败。它不会列出具有默认设置但未被覆盖的参数。
  • 你知道有一个包会导出这样的函数(只有...作为参数)吗?
  • 当 tmpfun 从另一个包装函数接收参数时,这不起作用。 (该列表只有未评估的参数)
【解决方案3】:

试试args函数

mean 函数的参数是什么?

> args(mean)
function (x, ...) 
NULL

lm 函数呢?

    > args(lm)
function (formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ...) 
NULL

如果您想获取参数列表,请尝试

as.list(args(lm))

【讨论】:

  • 很糟糕的是,更多的函数不配合 args 调用,例如 predict。所以骗子不得不去别处记住你试图记住的一个参数/标志。
【解决方案4】:

在搜索相关内容时偶然发现了这个问题。虽然我意识到这已经有好几年了,但回答似乎并不令人满意,而且似乎没有任何现成的解决方案。

可以使用formalsenvironment 函数的组合来制作(不优雅的)解决方法。下面的示例使用从形式中提取的名称从环境中提取参数,然后附加省略号列表。如果您希望获得在函数调用时设置的值,请​​将 orig_values 参数设置为 TRUE。该函数仅包括在函数调用时隐式或显式设置的变量。

allargs <- function(orig_values = FALSE) {
  # get formals for parent function
  parent_formals <- formals(sys.function(sys.parent(n = 1)))

  # Get names of implied arguments
  fnames <- names(parent_formals)

  # Remove '...' from list of parameter names if it exists
  fnames <- fnames[-which(fnames == '...')]

  # Get currently set values for named variables in the parent frame
  args <- evalq(as.list(environment()), envir = parent.frame())

  # Get the list of variables defined in '...'
  args <- c(args[fnames], evalq(list(...), envir = parent.frame()))


  if(orig_values) {
    # get default values
    defargs <- as.list(parent_formals)
    defargs <- defargs[unlist(lapply(defargs, FUN = function(x) class(x) != "name"))]
    args[names(defargs)] <- defargs
    setargs <- evalq(as.list(match.call())[-1], envir = parent.frame())
    args[names(setargs)] <- setargs
  }
  return(args)
}


tempf <- function(a, b = 2, ...) {
  d <- 5
  b <- 3

  cat("Currently set values defined in call or formals\n")
  print(allargs())
  cat("Values as defined at the time of the call\n")
  print(allargs(T))
}

tempf(1, c = 3)

Currently set values defined in call or formals
$a
[1] 1

$b
[1] 3

$c
[1] 3

Values as defined at the time of the call
$a
[1] 1

$b
[1] 2

$c
[1] 3

【讨论】:

    【解决方案5】:

    相信你在找formals:

    formals(sd)
    $x
    
    
    $na.rm
    [1] FALSE
    

    在此使用dput 会为您提供您在问题中指定的形式:

    dput(formals(sd))
    list(x = , na.rm = FALSE)
    

    请注意,formals 不适用于 原始 函数,只能用于闭包。

    【讨论】:

    • 这只列出了 default 参数。
    【解决方案6】:

    rlang::fn_fmls 给出了一个简洁干净的解决方案:

    library(ggplot2)
    library(rlang)
    
    # action
    argument_list <- rlang::fn_fmls(fn = geom_point)
    
    # evaluate output
    class(argument_list)
    #> [1] "pairlist"
    
    is.list(argument_list)
    #> [1] TRUE
    
    argument_list
    #> $mapping
    #> NULL
    #> 
    #> $data
    #> NULL
    #> 
    #> $stat
    #> [1] "identity"
    #> 
    #> $position
    #> [1] "identity"
    #> 
    #> $...
    #> 
    #> 
    #> $na.rm
    #> [1] FALSE
    #> 
    #> $show.legend
    #> [1] NA
    #> 
    #> $inherit.aes
    #> [1] TRUE
    

    reprex package (v0.3.0) 于 2020 年 2 月 25 日创建

    【讨论】:

      【解决方案7】:
      test <- function(
        x = 1,
        y = 2,
        ...
      ) {
        if(length(list(...)) == 0) {
          print(as.list(environment()))
        } else {
          print(c(as.list(environment()), list(...)))
        }
      }
      
      test()
      test(z = 3)
      

      【讨论】:

      • 与已经提出的解决方案相比,使用这种方法有什么好处?特别是,这似乎与 user399470 的答案非常相似
      猜你喜欢
      • 1970-01-01
      • 2018-02-14
      • 2010-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多