为何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
相关产品推荐
相关产品推荐

