且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何找出在R函数调用中使用了哪些参数值?

更新时间:2023-11-08 22:01:46

这确实不是一件容易的事.如果要构建函数,则可以使用 match.call 捕获呼叫,可以轻松解析该呼叫:

This is really not an easy thing to do. If you're building the function, you can capture the call with match.call, which can be parsed without too much trouble:

f <- function(x, y = 1, ...){
    cl <- match.call()
    as.list(cl[-1])
}

str(f(1))
#> List of 1
#>  $ x: num 1

str(f(1, 'foo'))
#> List of 2
#>  $ x: num 1
#>  $ y: chr "foo"

str(f(1, 'foo', list(3), fun = sum))
#> List of 4
#>  $ x  : num 1
#>  $ y  : chr "foo"
#>  $    : language list(3)
#>  $ fun: symbol sum

注意 match.call 仅捕获呼叫,并且不添加默认参数(在第一个示例中没有 y ).可以使用 formals(f)来访问它们,因为 f 不是原始的,因此可以通过

Note match.call only captures the call, and doesn't add in default parameters (there's no y in the first example). Those can be accessed with formals(f), since f isn't primitive, so complete arguments could be created via

user_args <- f(1)
fun_args <- formals(f)
fun_args[names(user_args)] <- user_args

str(fun_args)
#> List of 3
#>  $ x  : num 1
#>  $ y  : num 1
#>  $ ...: symbol

这种方法不适用于完成的点,但是如果它们完成了,则 match.call 本身就足够了.要提取传递给现有函数的参数,可以使用 match.call 编写包装,但是重构每个函数几乎是不实际的,除非您覆盖现有函数,否则捕获的调用无论如何都会看起来很有趣..只要该函数不是原始函数,就可以使用 quote 启用 formals 方法,

This approach doesn't work well for completed dots, but if they're completed then match.call itself should suffice. To extract the parameters passed to an existing function, you could write a wrapper with match.call, but it's hardly practical to reconstruct every function, and the call you capture will look funny anyway unless you overwrite existing functions. As long as the function isn't primitive, you could use quote to enable the formals approach, though:

cl <- quote(rnorm(5, 2))
user_args <- as.list(cl[-1])    # subset call to only args
fun_args <- formals(as.character(cl[1]))    # subset call to only function
names(user_args) <- names(fun_args)[seq(length(user_args))]
fun_args[names(user_args)] <- user_args

str(fun_args)
#> List of 3
#>  $ n   : num 5
#>  $ mean: num 2
#>  $ sd  : num 1

另一种方法是使用rlang,其功能可以很好地处理原语( fn_fmls(sum)),可以轻松而可靠地提取部分调用( lang_fn lang_args ),准确命名未命名的参数( lang_standardize )等.连同purrr的新 list_modify (开发版)一起,这一切都变得很轻松:

Another approach is to use rlang, whose functions handle primitives well (fn_fmls(sum)), can extract parts of the call easily and reliably (lang_fn, lang_args), name unnamed parameters accurately (lang_standardize), and more. Together with purrr's new list_modify (dev version), it all becomes fairly painless:

library(rlang)

fun_call <- quo(rnorm(5))
fun_call
#> <quosure: frame>
#> ~rnorm(5)

default_args <- fn_fmls(lang_fn(fun_call))
str(default_args)
#> Dotted pair list of 3
#>  $ n   : symbol 
#>  $ mean: num 0
#>  $ sd  : num 1

user_args <- lang_args(lang_standardise(fun_call))
str(user_args)
#> List of 1
#>  $ n: num 5

calling_args <- purrr::list_modify(default_args, user_args)
str(calling_args)
#> Dotted pair list of 3
#>  $ n   : num 5
#>  $ mean: num 0
#>  $ sd  : num 1