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

为何exams2nops首次运行时重复执行Rmd代码致计数器异常?

问题描述

我在R exams的习题中添加全局计数器,统计生成试卷时习题的调用次数,发现运行exams2nops()时首次调用会被计数两次——测试显示.Rmd文件的代码首次运行时执行了两次。

我的NopsProblem.Rmd代码如下:

```{r data generation, echo = FALSE, results = "hide"}
envir <- .GlobalEnv
if (length(envir$N)==0) envir$N <- envir$num <- 0
envir$num <- envir$num + 1
Question

r num

Meta-information

extype: num
exsolution: 1
exname: problem

设计逻辑是首次运行时将计数器设为0并立即更新为1,后续每次调用计数器加1。运行`exams2pdf(c("NopsProblem.Rmd","NopsProblem.Rmd","NopsProblem.Rmd"))`时一切正常,但运行`exams2nops(c("NopsProblem.Rmd","NopsProblem.Rmd","NopsProblem.Rmd"))`时,第一道题的计数器起始值为2。请问这是bug还是操作有误?

# 解答
这不是操作错误,是`exams2nops()`的设计特性导致的。

`exams2nops()`生成试卷时,会先预运行一次习题来获取元信息(比如题型、分值、答案格式等),之后才正式生成试卷内容。这就导致首次调用的习题会被执行两次:一次是预检查元信息,一次是正式生成题目。而`exams2pdf()`没有这个预运行步骤,所以计数器表现正常。

可以通过两种方式解决:
- **放弃全局环境存储计数器**:改用`exams2nops()`的`envir`参数指定专用环境,避免预运行和正式运行的状态互相干扰;或者在习题内部通过调用上下文区分预运行与正式运行,只在正式运行时更新计数。
- **手动控制计数逻辑**:不依赖习题内部的运行次数计数,而是在调用`exams2nops()`时,通过循环或参数传递给每个题目手动添加序号,这种方式更稳定,不受预运行影响。

举个修改后的代码示例,通过判断运行阶段更新计数器:
```r
```{r data generation, echo = FALSE, results = "hide"}
# 创建专用计数器环境,避免污染全局空间
if (!exists("exam_counter", envir = .GlobalEnv)) {
  assign("exam_counter", list(num = 0), envir = .GlobalEnv)
}

# 判断是否为正式生成阶段:预运行时不会渲染完整题目内容,可通过调用栈识别
is_production <- length(sys.calls()) > 5 && grepl("weave", deparse(sys.calls()[[length(sys.calls())-1]]))

if (is_production) {
  exam_counter$num <- exam_counter$num + 1
}
Question

r exam_counter$num

Meta-information

extype: num
exsolution: 1
exname: problem

---
内容的提问来源于stack exchange,提问作者PaperBasket
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:29:53