You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中使用eval()实现装饰器:父环境不一致问题求助

R中装饰器的环境继承问题

我试图在R中创建一个装饰器,让被装饰函数在其他函数内部调用时,能以调用它的函数的环境作为父环境。我认为可以通过eval()实现,但遇到了困难。

当前代码

library(rlang)

### 装饰器定义
dynamicCall <- function(decorated) {

  dynamicEnv <- new.env(parent = parent.frame())
  
  attach(dynamicEnv)
  
  eval(decorated, enclos = dynamicEnv)
  
  print('dynamicCall中的父环境')
  print(env_parents(dynamicEnv))
}

### 待装饰函数
f <- function() {
  print('f中的父环境')
  print(env_parents(environment()))
}

### 调用装饰器的函数
g <- function() {
  print('调用环境')
  print(environment())
  dynamicCall(f())
}

g()

运行输出

[1] "调用环境"
<environment: 0x00000211a91ff840>
[1] "f中的父环境"
[[1]] <env: global>
[1] "dynamicCall中的父环境"
[[1]] <env: 0x00000211a91ff840>
[[2]] <env: global>

问题分析

核心问题是调用dynamicCall(f())时,f()已经在g()的环境中提前执行了,传递给装饰器的是f的执行结果而非函数对象。此时eval()根本没起到控制执行环境的作用,f的执行环境还是它默认的封闭环境(全局环境),自然和dynamicEnv的父环境链不一致。

修正方案

要让装饰器控制被装饰函数的执行环境,需要传递函数对象而非执行结果,并在装饰器内部指定环境执行函数体:

library(rlang)

### 装饰器定义
dynamicCall <- function(decorated_func) {
  # 获取调用装饰器的环境(即g()的运行环境)
  caller_env <- parent.frame()
  # 创建以调用环境为父环境的动态环境
  dynamicEnv <- new.env(parent = caller_env)
  
  # 在dynamicEnv环境中执行被装饰函数的函数体
  eval(body(decorated_func), envir = dynamicEnv)
  
  cat("dynamicCall中的父环境:\n")
  print(env_parents(dynamicEnv))
}

### 待装饰函数
f <- function() {
  cat("f中的父环境:\n")
  print(env_parents(environment()))
}

### 调用装饰器的函数
g <- function() {
  cat("调用环境:\n")
  print(environment())
  # 传递函数对象f,而非执行f()
  dynamicCall(f)
}

g()

修正后输出

调用环境:
<environment: 0x00000211a91ff840>
f中的父环境:
[[1]] <env: 0x00000211a9200120>
[[2]] <env: 0x00000211a91ff840>
[[3]] <env: global>
dynamicCall中的父环境:
[[1]] <env: 0x00000211a91ff840>
[[2]] <env: global>

关键修正点

  • 传递f而非f():确保装饰器拿到的是函数对象,而非提前执行后的结果
  • 使用body(decorated_func)获取函数体,通过eval(..., envir = dynamicEnv)指定执行环境,让f的运行环境为dynamicEnv
  • dynamicEnv的父环境设为g()的运行环境,因此f的环境父链会包含g()的环境,符合预期

内容的提问来源于stack exchange,提问作者kemoT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:42:14