获取列表中的所有参数

R 是否提供了一个 object/function/method/关键字来获取所有的函数参数?

举个例子: function(a, b="default", ...)将在功能环境中提供 ab以及 ...。是否有一个类似于 list(...)的声明,也将包括 ab在结果中?

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

47124 次浏览

try args function

What are the arguments for mean function?

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

What about lm function?

    > 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

If you want to get a list of arguments try

as.list(args(lm))

I believe you are looking for formals:

formals(sd)
$x




$na.rm
[1] FALSE

And using dput on this gives you the form you specify in the question:

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

Note that formals doesn't work for primitive functions, only closures.

I think that you want 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

One solution is to use:

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

This creates a named list of the argument values.

Stumbled upon this question while searching for something related. While I realize that this is several years old, the responses appear unsatisfactory, and there does not appear to be any off-the-shelf solution to the question.

It is possible to make an (inelegant) workaround, using a combination of the formals and environment functions. The example below extracts arguments from the environment using names extracted from formals, then appends the ellipsis-list. If you wish to have the values as they were set at the time of function call, set the orig_values argument to TRUE. The function only includes variables implicitly or explicitly set at function call.

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
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)

rlang::fn_fmls gives a brief and clean solution:

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

Created on 2020-02-25 by the reprex package (v0.3.0)

The function by @Intelligentaccident was almost exactly what I was after. The only problem I had was some functions I needed it for had ...'s and others didn't. I have made his code even more inelegant (actually, I thought it was pretty clear and well commented) in order to work with both types of function. Thanks so much @Intelligentaccident your code has made my life much easier.

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())[fnames]
  



# Get the list of variables defined in '...'
if (any(names(parent_formals) == '...')) args <- c(args,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)
}