关于函数的不同环境,我有几个问题。以下列例子为例:
environment(sd)
# <environment: namespace:stats>名称空间:stats是否指向函数sd的封闭环境?
pryr::where(sd)
# <environment: package:stats>package:stats指向函数sd的绑定环境吗?
根据高级R,哈德利韦翰的说法:“封闭环境属于函数,永远不会改变.”
但是,功能的封闭环境可以更改如下:
new.env <- new.env()
environment(f) <- new.env函数的环境属性指示函数的执行环境,对吗?一篇关于R在环境中发现东西的在线文章
总结我的问题:
stats包的这两种不同环境是什么?它类似于之前的一篇文章在这里。
发布于 2017-06-08 17:13:20
TLDR:
功能环境
在讨论函数时,您必须区分4种不同的环境:
find()为您提供绑定环境。environment()为您提供了封闭的环境。,为什么这很重要,
每个环境都有特定的功能:
emptyenv()。您可以更改封闭环境
实际上,您可以改变封闭的环境。它是包中函数的封闭环境,您不能更改它。在这种情况下,您不需要更改封闭环境,而是在新环境中创建一个副本:
> ls()
character(0)
> environment(sd)
<environment: namespace:stats>
> environment(sd) <- globalenv()
> environment(sd)
<environment: R_GlobalEnv>
> ls()
[1] "sd"
> find("sd")
[1] ".GlobalEnv" "package:stats" # two functions sd now
> rm(sd)
> environment(sd)
<environment: namespace:stats>在这种情况下,第二个sd将全局环境作为封装和绑定环境,但是原始的sd仍然存在于包环境中,其封闭环境仍然是该包的命名空间。
当您执行以下操作时,可能会出现混淆:
> f <- sd
> environment(f)
<environment: namespace:stats>
> find("f")
[1] ".GlobalEnv"这里发生了什么?封闭环境仍然是命名空间''stats'‘。这就是创建函数的地方。然而,绑定环境现在是全球环境。这就是名称"f“绑定到对象的地方。
我们可以将封闭环境更改为一个新的环境e。如果现在检查,则封闭环境变为e,但e本身是空的。f仍然绑定在全球环境中。
> e <- new.env()
> e
<environment: 0x000000001852e0a8>
> environment(f) <- e
> find("f")
[1] ".GlobalEnv"
> environment(f)
<environment: 0x000000001852e0a8>
> ls(e)
character(0)e的封闭环境是全球环境。因此,f的工作方式仍然好像它的外壳是全球环境。环境e包含在其中,因此如果在e中找不到什么东西,则函数将在全局环境中查找,依此类推。
但是因为e是一个环境,R调用了一个父环境。
> parent.env(e)
<environment: R_GlobalEnv>
> f(1:3)
[1] 1 名称空间和包环境
这个原则也是软件包使用的“技巧”:
这样做的原因很简单:对象只能在您所处的环境中或在其封闭的环境中找到。
一个例子:

现在假设您创建了一个以空环境作为父环境的环境。如果您将此用作函数的封闭环境,则不再起作用。因为现在您绕过了所有的包环境,所以再也找不到一个函数了。
> orphan <- new.env(parent = emptyenv())
> environment(f) <- orphan
> f(1:3)
Error in sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), :
could not find function "sqrt"父帧
这才是有趣的地方。父框架或调用环境是查找作为参数传递的值的环境。但是父框架可以是另一个函数的本地环境。在这种情况下,R首先在另一个函数的本地环境中查找,然后在调用函数的封闭环境中,然后一直到全局环境,即附加包的环境,直到它到达空环境。这就是“找不到的对象”bug睡觉的地方。
发布于 2017-06-08 16:44:12
environment(function)给出了函数的封闭环境(即闭包),该环境被指定为指向定义函数的环境的指针。这个约定称为词法作用域,它允许您使用模式(如工厂函数)。下面是一个简单的例子
factory <- function(){
# get a reference to the current environment -- i.e. the environment
# that was created when the function `factory` was called.
envir = environment()
data <- 0
add <- function(x=1){
# we can use the lexical scoping assignment operator to re-assign the value of data
data <<- data + x
# return the value of the lexically scoped variable `data`
return(data)
}
return(list(envir=envir,add=add))
}
L = factory()
# check that the environment for L$add is the environment in which it was created
identical(L$envir,environment(L$add))
#> TRUE
L$add()
#> 1
L$add(3)
#> 4请注意,我们可以使用data重新分配封闭环境中的assign()值,如下所示:
assign("data",100,L$envir)
L$add()
#> 101此外,当我们再次调用函数factory()时,将创建另一个新环境,并将其分配为函数调用中定义的函数的闭包,这使得我们必须将foo$add()函式作用域分离到它们自己的单独环境中:
M = factory()
M$add()
#> 1
#> 2
L$add()
#> 102上面的工厂函数通过继续搜索变量(以及使用作用域赋值操作符)来说明函数与其包围环境之间的链接,而下面的函数通过承诺说明本地环境和调用框架之间的链接,这就是R在函数调用中传递变量的方式。
具体来说,当您调用一个函数时,R会为传递的变量和表达式的值创建承诺。当参数为force()'d或使用参数时,通过在调用环境中评估允诺来传递(复制)变量/表达式中的这些值--而不是更快!
例如,这个工厂函数接受一个作为承诺存储的参数,直到调用返回的函数为止:
factory2 <- function(x){
out <-function(){
return(x)
}
return(out)
}现在,在某些情况下,factory2的行为是直观的:
y = 1
f = factory2(y)
f()
#> 1但在其他情况下却并非如此:
y = 1
h = factory2(y)
y = 2
h()
#> 2因为对表达式y的承诺在调用h()之前是不计算的,在第二个示例中,y的值是2!当然,既然通过允诺评估将值从调用环境复制到本地环境中,更改y的值不会影响h()返回的值。
y = 3
h()
#> 2https://stackoverflow.com/questions/44427752
复制相似问题