我想编写一个后台程序,该程序检测R的全局环境的变化,并在任何变量被覆盖时提醒用户(在交互会话期间).

我修改了以下代码:

environment_changed <- function(before_env, after_env) {
  !identical(before_env, after_env)
}

check_environment_change <- function(before_env) {
  after_env <- as.list(.GlobalEnv)
  if (has_environment_changed(before_env, after_env)) {
    print("Change detected!")
    }
  }

addTaskCallback(check_environment_change)

x <- 1
x <- 2 # doesn't work

它不起作用.我真的不明白addTaskCallback是如何工作的,但我认为这可能是一种可能的方法.除此之外,还能如何实现这一点呢?

推荐答案

使用addTaskCallback()中的示例作为模板,我进行了以下操作.它使用times()参数来标识额外的回调将运行多少次(我目前已将其设置为Inf,因此您必须使用removeTaskCallback()将其关闭.它目前所做的是判断环境中在任务执行前后是否有相同的名称.然后,如果这些对象中的任何一个已更改,它将返回一条消息.下面是一个例子:

times <- function(total = Inf, before_env = as.list(.GlobalEnv)) {
  ctr <- 0
  function(expr, value, ok, visible) {
    check_environment_overwrite <- function(before_env) {
      after_env <- as.list(.GlobalEnv)
      olaps <- intersect(names(before_env), names(after_env))
      if(length(olaps) > 0){
        if(!identical(before_env[olaps], after_env[olaps])){
          out <- lapply(seq_along(olaps), \(i){
            identical(before_env[[olaps[i]]], 
                      after_env[[olaps[i]]])})
          outv <- do.call("c", out)
          names(outv) <- olaps
            cat("The following elements have changed in .GlobalEnv: ", 
                names(outv)[which(!outv)], "\n", sep="")
          }
      }
    }
    check_environment_overwrite(before_env)
    before_env <<- as.list(.GlobalEnv)
    ctr <<- ctr + 1
    keep.me <- (ctr < total)
    if (!keep.me)
      cat("handler removing itself\n")
    
    # return
    keep.me
  }
}

要获得相同的结果,请从不包括xz的工作区开始:

# > n <- addTaskCallback(times())
# > x <- 1
# > z <- 1
# > x <- 2
# The following elements have changed in .GlobalEnv: x
# > z <- 1
# > z <- 2
# The following elements have changed in .GlobalEnv: z
# > 
# > removeTaskCallback(n)
# [1] TRUE

Edit: alternative assignment operator that checks overwriting beforehand

本着这个问题的精神,上面的函数将在您覆盖某些内容后通知您.我们可以使用另一个赋值操作符来查看某些内容是否会被覆盖,如果会,它会询问用户是否要覆盖它.

`%a%` <- function(lhs, rhs){
  lhs_name <- as.character(substitute(lhs))
  if(lhs_name %in% names(.GlobalEnv)){
   rpl <- askYesNo(paste0("Do you want to replace ", lhs_name, " in .GlobalEnv")) 
   if(rpl){
     assign(lhs_name, rhs, envir = .GlobalEnv)
   }
  }else{
    assign(lhs_name, rhs, envir = .GlobalEnv)
  }
}
# > x %a% 1
# > x %a% 2
# Do you want to replace x in .GlobalEnv (Yes/no/cancel) Yes
# > x
# [1] 2

R相关问答推荐

在R中使用自定义函数时如何删除该函数的一部分?

在位置周围设定一个半径并识别该半径内的其他位置

向gggplot 2中的数据和轴标签添加大写和星号

如何使用R中的dhrr函数将李克特量表的因子列从长转换为宽?

如何在R中合并和合并多个rabrame?

如何动态更新selectizeInput?

是否可以创建一个ggplot与整洁判断的交互作用

计算时间段的ECDF(R)

如何编辑gMarginal背景以匹配绘图背景?

使用R闪光显示所有数据点作为默认设置

使用for循环和粘贴创建多个变量

R中边际效应包中Logistic回归的交互作用风险比

您是否可以使用facet_rap设置一个较低的限制来对ggmap上的比例中断进行zoom ?

仅在R中的数据集开始和结束时删除所有 Select 列的具有NA的行

R -使用矩阵reshape 列表

向R中的数据帧添加一列,该列统计另一列中每个唯一值的二进制观测值的数量

有没有办法通过str_Detect()或其他字符串匹配函数来连接两个长度不等的数据帧?

如何将EC50值绘制在R中的剂量-react 曲线上?

如何将图例文本添加到图例符号中

是什么打破了此Quarto仪表板中的工具提示?