【问题标题】:Parsing R function names, arguments, and return values解析 R 函数名称、参数和返回值
【发布时间】:2017-11-08 20:18:07
【问题描述】:

如何以编程方式解析函数、参数及其返回值的名称?

我有兴趣使用drakepackage 生成用于自动化 R 数据分析工作流的工作计划数据框。可以使用workplan 函数生成此类工作计划数据帧。

我有一个 R 脚本,其中包含我想使用的功能。例如:

funA <- function(x){
  y <- x + 2
  y
}

funB <- function(y){
  z <- y^2
  z
}

我想以编程方式生成如下所示的数据框。如何解析函数名称、参数和返回值,并使用 drake::workplan 或其他函数创建这样的 data.frame?

  target command
1     y  funA(5)    
2     z  funB(3)      

人们会像这样手动完成:

my_plan <- drake::workplan(z=funB(5), y=funA(3))

然后运行工作流:

drake::make(my_plan)

谢谢。

【问题讨论】:

  • 您想解析一个原始脚本文本文件而不执行它?还是您正在将这些对象加载到活动的 R 会话中?
  • @MrFlick:我想通过执行source("functions.R") 之类的操作来解析我正在加载到活动 R 会话中的对象。
  • 如果您真的想对特定文件进行源代码分析,您可以查看parse("functions.R")。我仍然认为您尝试做的事情有点不稳定,但是我对德雷克的了解还不够,无法给您任何真正的提示:/

标签: r reproducible-research


【解决方案1】:

你可以通过formals()获取参数

funA <- function(x, b = "default"){
  y <- x + 2
  y
}    
formals(funA)

您还可以使用body()environment() 提取函数的主体和环境

无法获取函数的名称。函数并没有真正的名字,一个名字指代一个函数(如果你不知道名字,你怎么知道引用什么?)。

也没有办法获取返回值。在您的示例中,您可以通过手动解析函数的body() 来获得zy,但这是一个非常糟糕的主意,并且只有在您编写函数源时才有效以特定的方式。即使你这样做了,也没有任何意义。 zy 在函数返回时被销毁。

也许您可以详细说明为什么您需要返回值和函数 namen,我相信还有另一种方法可以解决您想要实现的目标。

【讨论】:

  • 您可以使用lsf.str() 列出所有指向函数的变量。
  • 感谢@MrFlick 提供lsf.str() 提示。
  • @Stefan F:为什么手动解析函数体是个坏主意?
  • 我的意思是你的策略是从函数内部返回的变量的名称中获取函数的值的名称,这听起来是一个非常糟糕的主意。我试图在我的回答中解释它,我不知道如何更好地说明它。另请注意,您通过body() 获得的源代码可能与编写函数时的原始源代码不同(主要是格式化)。我认为你最好的办法是按照 hrbrmstr 的建议熟悉 parse()
  • 谢谢你的回答,@StefanF
【解决方案2】:

假设你有一个这样的源文件:

funA <- function(x, y){
  y <- x + 2
  y

}

funB <- function(y){
  z <- y^2
  z

}

命名为test.r,你可以这样做:

library(purrr)
library(dplyr)

fenv <- new.env()
parse("test.r") %>% 
  keep(is.language)  %>% 
  keep(~grepl(", function", toString(.x))) %>% 
  map(eval, envir=fenv) %>% 
  map_df(~{
    params <- list(names(formals(.x)))
    bdy <- deparse(body(.x))
    bdy <- bdy[length(bdy)-1]
    data_frame(target = trimws(bdy), params = params)
  }) %>% 
  mutate(fname = ls(fenv))

产生:

## # A tibble: 2 x 3
##   target    params fname
##    <chr>    <list> <chr>
## 1      y <chr [2]>  funA
## 2      z <chr [1]>  funB

这很脆弱,但不是脆弱,因为它在 eval 和临时环境分配之前过滤掉了语言对象和函数。

我假设您可以从 params 列中提取参数名称,然后最终生成您需要的内容。

【讨论】:

  • 谢谢你,@hrbrmstr。我会试试看。
猜你喜欢
  • 2015-07-19
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 2018-08-12
相关资源
最近更新 更多