代码之家  ›  专栏  ›  技术社区  ›  Denis Cousineau

R fn_env,带有字符串参数,用于获取函数的环境

  •  0
  • Denis Cousineau  · 技术社区  · 5 月前

    我想用R fn_env() 例如,使用字符串参数 my_fn_env("count") 程序的用户可以输入任何功能,也可以包括具有以下功能的功能 :: 符号。, "plyr::count" ,因此此函数应返回与 fn_env(plyr::count)

    我考虑过:

    do.call("fn_env", list("plyr::count"), quote=FALSE)
    

    但是作为参数给出的引号字符串仍然是引号。电子书《Advanced R》第7章( here )具有功能 where() 它在找到匹配时返回环境,接受字符串,但不接受 :: 符号,显然。

    有什么建议吗?

    1 回复  |  直到 5 月前
        1
  •  1
  •   Tim G    5 月前

    当然,我们可以编写一个函数来实现这一点! 首先,将输入字符串拆分为 ::

    • 如果没有拆分(长度=1),则将其视为常规函数名
    • 如果存在拆分(长度=2),则将第一部分视为包名,第二部分视为函数名

    然后它使用 get() getExportedValue() 以检索实际功能。 最后,它返回该函数的环境。

    这应该会给你与直接在函数上使用fn_env()相同的结果,但具有接受字符串输入的灵活性。

    using<-function(...) {
      libs<-unlist(list(...))
      req<-unlist(lapply(libs,require,character.only=TRUE))
      need<-libs[req==FALSE]
      if(length(need)>0){ 
        install.packages(need)
        lapply(need,require,character.only=TRUE)
      }
    }
    using("rlang")
    
    my_fn_env <- function(fun_name) {
      # Split the string in case it contains namespace specification
      parts <- strsplit(fun_name, "::")[[1]]
      
      if (length(parts) == 1) {
        # Case 1: Regular function name without namespace
        fn <- tryCatch(
          get(fun_name, mode = "function"),
          error = function(e) stop("Function '", fun_name, "' not found")
        )
        return(environment(fn))
      } else if (length(parts) == 2) {
        # Case 2: Function with namespace specification
        pkg <- parts[1]
        fun <- parts[2]
        
        # Check if package is installed and loaded
        if (!requireNamespace(pkg, quietly = TRUE)) {
          stop("Package '", pkg, "' is not installed")
        }
        
        # Get the function from the namespace
        fn <- tryCatch(
          getExportedValue(pkg, fun),
          error = function(e) stop("Function '", fun, "' not found in package '", pkg, "'")
        )
        return(environment(fn))
      } else {
        stop("Invalid function name format")
      }
    }
    
    # normal way using fn_env
    f <- function(x) x + y
    fn_env(f)
    
    # Test our function!
    my_fn_env("f") 
    
    my_fn_env("mean") 
    my_fn_env("plyr::count")