R:函数--显示环境名而不是环境的内存地址?

vd8tlhqk  于 2023-04-03  发布在  其他
关注(0)|答案(5)|浏览(131)

如何像内置函数一样显示函数内部的环境名称?例如,当我键入函数时:表示在基本包中可用,我可以将环境视为“namespace:base”。

mean

   function (x, ...) 
   UseMethod("mean")
   <bytecode: 0x0547f17c>
   **<environment: namespace:base>**

然而,当我将一个函数附加到新创建的环境中时,在这里访问函数(f)中的自由变量(z)的值,它会自动驻留在.GlobalEnv环境中,并且环境的名称不会显示在函数中,但可以看到(e1)环境的内存地址“0x051abd60”。

e1 <- new.env()
     e1$z <- 10
     f <- function(x) {
           x + z 
      }
     environment(f) = e1
     f

               function(x) {
                    x + z 
               }
               **<environment: 0x051abd60>**

为什么我会看到这种行为?为什么我不像R的内置函数那样在函数中获取我的环境名称,也可以从各种R包中获取函数?环境数据结构和.GlobalEnv环境之间有什么区别吗?从search()
任何指向这种行为背后动机的指针都将受到高度赞赏。
谢谢你

r6l8ljro

r6l8ljro1#

您可以使用attr设置环境名称,如下所示:

e <- new.env()
attr(e, "name") <- "xyzzy"

environmentName(e)
## [1] "xyzzy"
ujv3wf0j

ujv3wf0j2#

如果我没记错的话,包和命名空间的环境名是在C级别分配的。所以用户创建的环境不会显示名称。即使有一个名为environmentName()的(误导性命名的)基函数,你也不能在R中设置环境名。它只会返回在C级别分配的名称。它实际上只适用于包和命名空间,而不是其他环境。

pwuypxnk

pwuypxnk3#

大多数环境没有名字-环境的名字是环境的一个特殊属性,而不是指向该环境的对象的名字。例如,在下面的例子中,你希望f的环境的“名字”是什么?

e1 <- new.env()
e1$z <- 10
e2 <- e1
e3 <- e1

f <- function(x) {
  x + z 
}
environment(f) <- e1

identical(e1, e2)
identical(e1, e3)
pgccezyw

pgccezyw4#

您可以使用最近发布的包envnames,我开发的这个包正好可以解决这个问题。
在您的示例中,如果您使用包的environment_name()函数来检索函数f()的环境,则会得到"e1",而不是使用内置函数environmentName()得到的"",即:

library(envnames)
e1 <- new.env()
e1$z <- 10
f <- function(x) {
   x + z 
}
environment(f) = e1
environment_name(environment(f))

输出为:

[1] "e1"

在Hadley给出的例子中,许多环境指向同一个环境,你可以在一个命名数组中获得所有这些环境名称:

library(envnames)
e1 <- new.env()
e1$z <- 10
e2 <- e1
e3 <- e1

f <- function(x) {
  x + z 
}
environment(f) <- e1
environment_name(environment(f))

其中,输出包括每个环境的位置作为返回数组的names属性:

R_GlobalEnv R_GlobalEnv R_GlobalEnv 
       "e1"        "e2"        "e3"

最后,既然你提到 * 看到环境的内存地址并不能告诉我们很多 * 关于我们正在谈论的用户定义环境的信息,你可以使用内存地址作为environment_name()函数的输入参数来获取与内存地址相关联的环境(或多个环境)的名称
下面的代码片段和输出说明了这一点(其中代码在单个环境的 your 示例上运行):

> f
function(x) {
       x + z 
    }
<environment: 0x0000000013f15870>
> environment_name("<environment: 0x0000000013f15870>")
[1] "e1"
qyyhg6bp

qyyhg6bp5#

根据我的实验(不阅读C代码),environmentName()做了两件事:

  • 首先检查你的环境是否有一个.__NAMESPACE__.$spec["name"],其中.__NAMESPACE__.是一个环境,spec是一个命名的字符向量(顺便说一句,使你的环境成为一个命名空间)。
  • 如果未找到,福尔斯回退到attr(, "name")

但是设置attr(, "name")不会影响函数的打印方式。

# initiate
e <- new.env()
fun <- function() {}
environment(fun) <- e
e
#> <environment: 0x14b28d3a0>
fun
#> function() {}
#> <environment: 0x14b28d3a0>

# set attr(, "name") : environmentName() is changed, function still prints the same
attr(e, "name") <- "NAME1"
environmentName(e)
#> [1] "NAME1"
e
#> <environment: 0x14b28d3a0>
#> attr(,"name")
#> [1] "NAME1"
fun
#> function() {}
#> <environment: 0x14b28d3a0>

# Make it a "minimal" namespace with a name, new name takes precedence, function prints differently
e[[".__NAMESPACE__."]] <- as.environment(list(spec = c(name = "NAME2")))
isNamespace(e) 
#> [1] TRUE
environmentName(e)
#> [1] "NAME2"
e
#> <environment: namespace:NAME2>
#> attr(,"name")
#> [1] "NAME1"
fun
#> function() {}
#> <environment: namespace:NAME2>

创建于2023-03-29带有reprex v2.0.2
有了名称空间后,可以使用setNamespaceInfo()更改其名称

setNamespaceInfo("stats", "spec", c(name = "FOO"))
asNamespace("stats")
#> <environment: namespace:FOO>
``

相关问题