设置放置在.GlobalEnv外部的函数的环境 [英] Set the environment of a function placed outside the .GlobalEnv

查看:270
本文介绍了设置放置在.GlobalEnv外部的函数的环境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将自定义环境中的功能附加到全局环境中,同时掩盖可能的内部功能.

I want to attach functions from a custom environment to the global environment, while masking possible internal functions.

具体来说,假设f()使用内部函数g(),则:

Specifically, say that f() uses an internal function g(), then:

  1. f().GlobalEnvls(all=TRUE)中不可见.
  2. f()应该可以从.GlobalEnv使用.
  3. f()内部函数g()应该 not 不可见,并且 not .GlobalEnv中可用.
  1. f() should not be visible in .GlobalEnv with ls(all=TRUE).
  2. f() should be usable from .GlobalEnv.
  3. f() internal function g() should not be visible and not usable from .GlobalEnv.

首先让我们创建如下环境和功能:

First let us create environments and functions as follows:

assign('ep', value=new.env(parent=.BaseNamespaceEnv), envir=.BaseNamespaceEnv)
assign('e', value=new.env(parent=ep), envir=ep)
assign('g', value=function() print('hello'), envir=ep)
assign('f', value=function() g(), envir=ep$e)

ls(.GlobalEnv)
## character(0)

我现在应该跑步:

ep$e$f()
## Error in ep$e$f() (from #1) : could not find function "g"

实际上,f的调用环境是:

In fact, the calling environment of f is:

environment(get('f', envir=ep$e))
## <environment: R_GlobalEnv>

其中不存在g.

尝试更改f的环境会出现错误:

Trying to change f's environment gives an error:

environment(get('f', envir=ep$e))=ep
## Error in environment(get("f", envir = ep$e)) = ep : 
##   target of assignment expands to non-language object

显然它适用于:

environment(ep$e$f)=ep
attach(ep$e)

现在,根据需要,.GlobalEnv中只有f()可用,而g()则不可用.

Now, as desired, only f() is usable from .GlobalEnv, g() is not.

f()
[1] "hello"
g()
## Error: could not find function "g" (intended behaviour)

此外,.GlobalEnv中都看不到f()g(),但是很遗憾:

Also, neither f() nor g() are visible from .GlobalEnv, but unfortunately:

ls(.GlobalEnv)
## [1] "ep"

将与f()关联的环境设置为ep,将ep放置在.GlobalEnv中.
我正想避免混乱的全球环境.
我可以重置f的父环境而不在全局环境中看到它吗?

Setting the environment associated with f() to ep, places ep in .GlobalEnv.
Cluttering the Global environment was exactly what I was trying to avoid.
Can I reset the parent environment of f without making it visible from the Global one?

更新
根据您的反馈,建议您构建一个程序包以获取适当的名称空间服务.
包装不灵活.我的助手功能存储在项目子目录(例如hlp)中,其来源类似于source("hlp/util1.R").
这样,可以轻松地在项目基础上即时混合和更新脚本.

UPDATE
From your feedback, you suggest to build a package to get proper namespace services.
The package is not flexible. My helper functions are stored in a project subdir, say hlp, and sourced like source("hlp/util1.R").
In this way scripts can be easily mixed and updated on the fly on a project basis.

(在顶部添加了新的枚举列表)

(Added new enumerated list on top)

更新2

现在,此处是几乎完整的解决方案,不需要外部软件包.

An almost complete solution, which does not require external packages, is now here.

推荐答案

是软件包还是模块都可以正是您想要的.如果您对软件包缺乏灵活性不满意,建议您给‹modules›做个尝试:它们优雅地解决了您的问题,并允许您将任意R源文件视为模块:

Either packages or modules do exactly what you want. If you’re not happy with packages’ lack of flexibility, I suggest you give ‹modules› a shot: they elegantly solve your problem and allow you to treat arbitrary R source files as modules:

仅在隐藏"功能的前面加上点(g.g) 1 .将这些定义写入文件foo.r,并通过

Just prefix the "hidden" functions with a dot (g.g)1. Write these definitions to a file foo.r, and load it via

foo = import('foo')
foo$f()

import_package('foo', attach = TRUE)
f()

这满足了枚举中的所有要点.特别是,这两段代码都使调用者可以使用f而不是.g.此外,与使用source相比,模块还具有众多其他优势. /a>.

This fulfils all the points in your enumeration. In particular, both pieces of code make f, but not .g, available to the caller. In addition, modules have numerous other advantages over using source.

从技术角度上讲,您的代码会导致ep位于全局环境中,因为赋值environment(ep$e$f)=ep在全局环境中创建了>的副本.附加环境后,您可以删除该对象.但是,代码仍然存在问题(它比必要的复杂,而且正如Hong Ooi所述,您不应该对基本名称空间感到困惑).

On a more technical note, your code results in ep being inside the global environment because the assignment environment(ep$e$f)=ep creates a copy of ep inside your global environment. Once you’ve attached the environment, you can delete this object. However, the code still has issues (it’s more complex than necessary and, as Hong Ooi mentioned, you shouldn’t mess with the base namespace).

1 当前,这是模块用信号通知未导出对象的方式.未来版本的模块将允许不需要调整对象名称的另一种机制.

1 Currently, this is how modules signal unexported objects. A future version of modules will allow another mechanism that doesn’t require adjusting the object’s name.

这篇关于设置放置在.GlobalEnv外部的函数的环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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