如何获取函数默认参数的具体值?除eval()外的替代方法
无需eval()复用并扩展SGP::capwords()默认special.words参数的方法
问题背景
调用SGP包的capwords()函数时,想要复用默认的special.words参数值,同时添加自定义词汇(比如"GPT")。最初尝试的代码:
capwords("What do you think about chat GPT version IV", c(formals(capwords)$special.words,"GPT"))
预期输出:
"What Do You Think About Chat GPT Version IV"
但实际输出中"IV"被转为"Iv":
"What Do You Think About Chat GPT Version Iv"
原因是formals(capwords)$special.words返回的是call类型的延迟表达式,而非实际的词汇列表,导致默认的"IV"没有被正确识别。
目前用eval()可以解决问题:
capwords("What do you think about chat GPT version IV", c(eval(formals(capwords)$special.words),"GPT"))
输出符合预期,但希望避免直接使用eval(),同时找到通用的解决方案。
替代方法
1. 直接复制源码中的默认参数列表
执行print(SGP::capwords)查看函数源码,可提取special.words的默认定义:
default_specials <- c("A", "An", "The", "And", "But", "Or", "For", "Nor", "As", "At", "By", "For", "From", "In", "Into", "Near", "Of", "On", "Onto", "To", "With", "IV", "VI", "VIII", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX")
直接用这个列表扩展自定义词汇:
capwords("What do you think about chat GPT version IV", c(default_specials, "GPT"))
- 优点:完全避免
eval(),代码直观 - 缺点:如果SGP包更新了
special.words的默认值,需要手动同步这个列表
2. 封装默认参数获取逻辑
写一个辅助函数隐藏eval()的调用,让业务代码更整洁:
get_capwords_default_specials <- function() { # 在capwords函数的环境中计算默认参数表达式 eval(formals(SGP::capwords)$special.words, envir = environment(SGP::capwords)) } # 调用时直接使用 capwords("What do you think about chat GPT version IV", c(get_capwords_default_specials(), "GPT"))
- 优点:自动同步包的默认参数更新,业务代码中看不到
eval() - 缺点:内部仍依赖
eval(),但封装后更通用易维护
3. 利用do.call计算默认表达式
通过do.call结合函数环境来计算默认参数的实际值,写法上比直接用eval()更贴近函数调用逻辑:
default_specials <- do.call(formals(SGP::capwords)$special.words, envir = environment(SGP::capwords)) capwords("What do you think about chat GPT version IV", c(default_specials, "GPT"))
- 优点:避免在业务代码中直接写
eval(),逻辑更清晰 - 缺点:本质仍是计算延迟表达式,和
eval()原理一致
总结
由于R支持函数默认参数的延迟计算,想要完全绕开eval()类的表达式计算,只能通过复制源码中的静态默认列表。如果需要自动同步包的更新,封装表达式计算逻辑的辅助函数是更实用的方案,既保证代码整洁,又能跟随包的参数变化。
内容的提问来源于stack exchange,提问作者Sergey V.
相关产品推荐
相关产品推荐

