R中不同的封闭环境,功能环境等 [英] Distinct enclosing environment, function environment, etc. in R

查看:96
本文介绍了R中不同的封闭环境,功能环境等的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对函数的不同环境有一些疑问.请看以下示例:

environment(sd)
# <environment: namespace:stats>

namespace:stats是否指向函数sd的封闭环境?

pryr::where(sd) 
# <environment: package:stats>

package:stats是否指向sd函数的绑定环境?

根据 Hadley Wickham的Advanced R :封闭环境属于功能,永不改变..."

但是函数的封闭环境可以如下更改:

new.env <- new.env()
environment(f) <- new.env

函数的环境属性指示函数的执行环境,对吗? 有关R在环境中寻找东西的在线文章

总结我的问题:

  1. 我们真的可以更改函数的封闭环境吗?
  2. stats软件包的两种不同环境是什么?
  3. 函数的环境是什么?

这与先前的帖子在此处类似.

解决方案

TLDR:

    实际上,您可以更改封闭环境. Hadley可能正在谈论打包功能.
  1. 封闭和绑定环境.你是对的.
  2. 那是执行环境.它仅在函数运行时存在.


功能环境

在谈论一个功能时,您必须区分4种不同的环境:

  • 绑定环境是找到功能的环境(即名称存在的环境).这是将对象实际绑定到其名称的地方. find()为您提供绑定环境.
  • 封闭环境是最初创建功能的环境.这不一定与绑定环境相同(请参见下面的示例). environment()为您提供了封闭的环境.
  • 本地环境是函数中的环境.您称其为执行环境.
  • 父框架或调用环境是调用该函数的环境.

为什么要这么做

每种环境都有特定的功能:

  • 绑定环境是您找到函数的环境.
  • 本地环境是R在其中寻找对象的第一个环境.
  • 一般规则是:如果R在本地环境中找不到对象,那么它将在封闭的环境中进行查找,依此类推.最后一个封闭环境始终是emptyenv().
  • 父框架是R查找传递为的对象的值的位置 争论.

您可以更改封闭环境

实际上,您可以更改封闭环境.这是您无法更改的来自包的功能 的封闭环境.在这种情况下,您无需更改封闭环境,而是实际上在新环境中创建一个副本:

> 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首先在其他函数的本地环境中查找,然后在调用函数的封闭环境中查找,一直到全局环境(即附加程序包的环境)为止.直到到达空的环境.这就是找不到对象"错误的所在.

I have a few questions about the different environments of a function. Take the following example:

environment(sd)
# <environment: namespace:stats>

Does namespace:stats point to the enclosing environment of function sd?

pryr::where(sd) 
# <environment: package:stats>

Does package:stats point to the binding environment of function sd?

According to Advanced R by Hadley Wickham: "The enclosing environment belongs to the function, and never changes..."

But the enclosing environment of function can be changed like the below:

new.env <- new.env()
environment(f) <- new.env

A function' environment property indicates a function's executing environment, correct? An online article regarding R finding stuff through environments

To sum up my questions:

  1. Can we actually change the enclosing environment of a function or not?
  2. What are those two different environments of the stats package?
  3. What is the function's environment?

It's similar to a previous post in here.

解决方案

TLDR:

  1. indeed, you can change the enclosing environment. Hadley was probably talking about packaged functions.
  2. the enclosing and the binding environment. You were correct.
  3. that's the execution environment. It only exists for the time the function runs.


Function environments

You have to distinguish 4 different environments when talking about a function:

  • the binding environment is the environment where the function is found (i.e. where its name exists). This is where the actual binding of an object to its name is done. find() gives you the binding environment.
  • the enclosing environment is the environment where the function is originally created. This is not necessarily the same as the binding environment (see examples below). environment() gives you the enclosing environment.
  • the local environment is the environment within the function. You call that the execution environment.
  • the parent frame or calling environment is the environment from where the function was called.

Why does this matter

Every environment has a specific function:

  • the binding environment is the environment where you find the function.
  • the local environment is the first environment where R looks for objects.
  • the general rule is: if R doesn't find an object in the local environment, it then looks in the enclosing environment and so on. The last enclosing environment is always emptyenv().
  • the parent frame is where R looks for the value of the objects passed as arguments.

You can change the enclosing environment

Indeed, you can change the enclosing environment. It is the enclosing environment of a function from a package you cannot change. In that case you don't change the enclosing environment, you actually create a copy in the new environment:

> 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>

In this case, the second sd has the global environment as the enclosing and binding environment, but the original sd is still found inside the package environment, and its enclosing environment is still the namespace of that package

The confusion might arise when you do the following:

> f <- sd
> environment(f)
<environment: namespace:stats>
> find("f")
[1] ".GlobalEnv"

What happens here? The enclosing environment is still the namespace ''stats''. That's where the function is created. However, the binding environment is now the global environment. That's where the name "f" is bound to the object.

We can change the enclosing environment to a new environment e. If you check now, the enclosing environment becomes e, but e itself is empty. f is still bound in the global environment.

> e <- new.env()
> e
<environment: 0x000000001852e0a8>
> environment(f) <- e
> find("f")
[1] ".GlobalEnv"
> environment(f)
<environment: 0x000000001852e0a8>
> ls(e)
character(0)

The enclosing environment of e is the global environment. So f still works as if its enclosure was the global environment. The environment e is enclosed in it, so if something isn't found in e, the function looks in the global environment and so on.

But because e is an environment, R calls that a parent environment.

> parent.env(e)
<environment: R_GlobalEnv>
> f(1:3)
[1] 1 

Namespaces and package environments

This principle is also the "trick" packages use:

  • the function is created in the namespace. This is an environment that is enclosed by the namespaces of other imported packages, and eventually the global environment.
  • the binding for the function is created in the package environment. This is an environment that encloses the global environment and possible other packages.

The reason for this is simple: objects can only be found inside the environment you are in, or in its enclosing environments.

  • a function must be able to find other functions(objects), so the local environment must be enclosed by possibly the namespaces of other packages it imports, the base package and lastly the global environment.
  • a function must be findable from within the global environment. Hence the binding (i.e. the name of the function) must be in an environment that is enclosed by the global environment. This is the package environment (NOT the namespace!)

An illustration:

Now suppose you make an environment with the empty environment as a parent. If you use this as an enclosing environment for a function, nothing works any longer. Because now you circumvent all the package environments, so you can't find a single function any more.

> 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"

The parent frame

This is where it gets interesting. The parent frame or calling environment, is the environment where the values passed as arguments are looked up. But that parent frame can be the local environment of another function. In this case R looks first in that local environment of that other function, and then in the enclosing environment of the calling function, and so all the way up to the global environment, the environments of the attached packages until it reaches the empty environment. That's where the "object not found" bug sleeps.

这篇关于R中不同的封闭环境,功能环境等的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆