人们经常使用attach()
和 detach()
在 R 中为变量名称设置“搜索路径”的函数,但是因为这会改变难以跟踪的全局状态,people推荐using with()
instead ,它会在单个表达式的持续时间内对搜索路径进行临时更改。
但是我只是注意到不像 attach()
, with()
显然没有“解决”功能 .例如,让我们首先设置一个虚拟函数,它将访问一个名为 x
的变量。 :
f <- function { print(x) }
现在,
with(list(x=42), f())
即使失败了
with(list(x=42), print(x))
和
attach(list(x=42))
f()
都成功了! :(
谁能告诉我为什么?我要
with()
表现得完全像 attach()
在这里,使我能够通过设置包含参数值的环境有效地将大参数列表传递给函数 with()
.我认为这种方法比其他方法有几个好处(我考虑过的两个是(a)费力地将所有参数传递给函数,以及(b)显式传递参数列表/框架作为函数参数并具有函数本身调用 with()
),但它不起作用。老实说,我发现这种差异非常令人不安!任何解释/帮助将不胜感激。我正在使用 R 2.11.1。
最佳答案
什么with(list(x = 42), f())
的区别正在做,而您期望的是词法作用域(这是 R 使用的)和动态作用域(这似乎是您所期望的)之间的区别。
词法作用域意味着在 x
的环境中查找自由变量(如 f
中的变量 f
)。已定义——不是环境 f
被称为从。f
在全局环境中定义,因此 x
被查找。
没关系with
已被调用来创建一个新环境,f
被调用是因为调用它的环境不涉及查找自由变量。
要使其按照您希望的方式工作,请创建 f
的副本并重置其环境,因为这是 R 用来搜索自由变量的环境:
with(list(x = 42), { environment(f) <- environment(); f() })
诚然,这有点繁琐,但您可以通过使用 proto 包来简化它,因为
proto
重置显式插入到 proto 对象中的每个函数的环境:library(proto)
with(proto(x = 42, f = f), f())
添加:
请注意,如果您的目标是进行面向对象编程(根据您对另一个回复的评论),那么您可能希望在 proto home page 上进一步研究 proto。 .例如,我们可以定义 proto 对象
p
并重新定义 f
所以它是p
的方法(在这种情况下,它必须接受参数 1 中的对象),如下所示:library(proto)
p <- proto(x = 42, f = function(.) print(.$x))
p$f()
添加2:
使用随附的案例,运行
f()
首先查看全局环境,因为f
被定义为。由于x
在全局环境中找不到它会查看全局环境的父级,在这种情况下它会在那里找到它。我们可以使用 parent.env
发现全局环境的父级。在这里我们看到附加环境已经成为全局环境的父级。> attach(list(x = 42))
> parent.env(.GlobalEnv)
<environment: 0x048dcdb4>
attr(,"name")
[1] "list(x = 42)"
我们可以按如下顺序查看全局环境及其所有祖先:
> search()
[1] ".GlobalEnv" "list(x = 42)" "package:stats"
[4] "package:graphics" "package:grDevices" "package:utils"
[7] "package:datasets" "package:methods" "Autoloads"
[10] "package:base"
因此
"list(x = 42)"
是全局环境的父级,stats 是 "list(x = 42)"
的父级等等。
关于r - R 中 with() 和 attach() 之间的行为有细微的不同吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7485881/