R: 如何检查对象是否存在于函数内部?

R: How to check whether object exists inside function?

问题

我需要检查一个对象是否存在于内部一个函数中,而不是其他地方。我该怎么做?

为了阐明我的意思,我使用 exists:

fun <- function(){exists("x")}
x <- 1
fun()
> TRUE

我对上述代码的预期输出是 FALSE,因为变量 x 是在 函数之外创建的。所以 x 保存在全局环境中,这就是函数 returns TRUE 的原因,但是我们能以某种方式测试 x 是否在 "function environment" 中吗?


我试过了

我发现 在我的情况下也不起作用。他们在那里建议使用

library(rlang)

f1 <- function(x){ 
  arg <- quo_name(enquo(x))
  if(exists(arg, where = .GlobalEnv)){
    return(2*x)
  } else {
    cat('variable ', '`', arg, '`', ' does not exist', sep = "")
  }
}

我希望以下两种情况的输出为 variable x does not exist,但如果 x 定义在 外部 之前的函数中,则情况并非如此:

x <- 1
f1(x)
> 2

rm(x)
f1(x)
variable `x` does not exist

我们可以通过为 exists 指定一个特定的环境来搜索并告诉它 看那里,而不是在封闭的环境中。

where= 参数告诉 exists 在何处寻找该对象。我们可以使用 environment() 明确指定它(returns 当前环境),或者使用默认值 -1R_GlobalEnv 从环境列表中删除以进行搜索.

无论哪种方式,关键是设置inherits=FALSE将其限制为指定的环境。否则,它还会查看我们不需要的封闭环境(如 R_GlobalEnv):

x <- 1
fun <- function(){exists("x", inherits = F)}

fun()
[1] FALSE

但是如果我们在函数的环境中定义 x,它 returns TRUE:

fun <- function(){
    x<-3;
    exists("x", inherits = F)}
fun()
[1] TRUE

明确定义环境的例子:

fun <- function(){exists("x", where = environment(), inherits = F)}

默认的 where=-1 参数发生了什么?该文档说,如果您为它提供一个整数,它会根据“搜索列表中的位置”选择环境。我们可以看到.GlobalEnv在位置1,后面是附加包

rm(list=ls()) # clear .GlobalEnv
x <- 3  # Add x to .GlobalEnv
ls()    # Show that x is the only thing in .GlobalEnv
[1] "x"

search() # Show the search list
 [1] ".GlobalEnv"        "package:lubridate" "package:forcats"   "package:stringr"  
 [5] "package:dplyr"     "package:purrr"     "package:readr"     "package:tidyr"    
 [9] "package:tibble"    "package:ggplot2"   "package:tidyverse" "tools:rstudio"    
[13] "package:stats"     "package:graphics"  "package:grDevices" "package:utils"    
[17] "package:datasets"  "package:methods"   "Autoloads"         "package:base"     

现在我们运行这个函数通过整数值检查不同环境中的不同对象:

fun <- function(){
    y <- 3
    k <- function(){
        z <- 3
        print(exists('z', -1, inherit=FALSE))
        print(exists('x', 1, inherit=FALSE))
        print(exists('y', parent.frame(), inherit=FALSE))}
    k()
    print(exists('x', -1, inherit=FALSE))
    print(exists('y', -1, inherit=FALSE))
    print(exists('x', 1, inherit=FALSE))
    print(exists('ymd', 2, inherit=FALSE))
    print(exists('last2', 3, inherit=FALSE))
    print(exists('str_detect', 4, inherit=FALSE))
}

> fun()
[1] TRUE   # Inside k(), -1 is the function env for k() - z is there
[1] TRUE   # 1 is .GlobalEnv, x is there
[1] TRUE   # to choose parent env with y, we need to specify it with parent.frame()
[1] FALSE  # -1 is the function env, x not in function env
[1] TRUE   # -1 is the function env, y is in function env
[1] TRUE   # 1 is .GlobalEnv, x is in .GlobalEnv
[1] TRUE   # position 2 is the lubridate package
[1] TRUE   # position 3 is the forcats package
[1] TRUE   # position 4 is the stringr package

从这里我们可以看出,-1 始终是当前函数的本地环境,而 1 是 .GlobalEnv,更大的数字是 search() 列出的附加包。如果你想更详细地指定,例如从 k() 中查看 fun(),那么你需要明确指定环境,或者使用像上面的 parent.frame() 这样的相对函数,或者通过将环境作为对象并直接引用如下:

fun <- function(){
    y <- 3
    env <- environment()
    k <- function(e){
        z <- 3
        print(exists('y', inherit=FALSE))
        print(exists('y', where=e, inherit=FALSE))
        }
    k(env)
}
fun()
[1] FALSE
[1] TRUE

另一种选择是使用 ls:

f1 <- function() { "x" %in% ls() }

f2 <- function() { x <- 1; "x" %in% ls() }

x <- 1

f1()
#> [1] FALSE
f2()
#> [1] TRUE

reprex package (v2.0.1)

于 2022-02-04 创建