How to make variable available to namespace at loading time
Following the approach in this answer to a related question, you can change your .onLoad()
function like so:
.onLoad <- function(libname, pkgname) {
variable <- some_function()
assign("variable", variable, envir = parent.env(environment()))
}
Then you can access variable
without attaching the package using MyRPackage:::variable
. I don't know what you do with some_function()
, so I tried the following with a dummy package:
.onLoad <- function(libname, pkgname) {
variable <- 42
assign("variable", variable, envir = parent.env(environment()))
}
And in a fresh R session the result was
> MyRPackage:::variable
[1] 42
Further explanation
From Hadley Wickham's Advanced R:
There are four special environments:
...
- The environment() is the current environment.
...
You can list the bindings in the environment’s frame with ls() and
see its parent with parent.env().
So, if we modify the .onLoad()
function further, we can see this in action:
.onLoad <- function(libname, pkgname) {
print(environment()) # For demonstration purposes only;
print(parent.env(environment())) # Don't really do this.
variable <- 42
assign("variable", variable, envir = parent.env(environment()))
}
Then starting an R session results in
<environment: 0x483da88>
<environment: namespace:MyRPackage>
being printed to the console at the start of the session. This allows you to assign variable
in the environment namespace:MyRPackage
even though trying assign("variable", variable, envir = namespace:MyRPackage)
would result in the error
Error: package or namespace load failed for ‘MyRPackage’:
.onLoad failed in loadNamespace() for 'MyRPackage', details:
call: get(name, envir = ns, inherits = FALSE)
error: object 'namespace' not found
when installing the package.
How do I assign variables to be available when an R package is loaded?
Although .onLoad
is one option, I think that it wouldn't be the recommended way to go about this (we can read here for what .onLoad
is mainly used).
The question is, do you want my_colors
to be available to the users? Or do you just want it to be available as internal data for your functions. From looking at your github repo I think the latter is the case, but lets go through both options. They are both explained in the link above from @Waldi's answer.
Make the colors and palettes available as external data to the user. You would do this with
usethis::use_data(my_colors)
and then you'd just need to document the data, but do not use@export
in the documentation. In the description file you could setLazyData: true
so the data is only loaded into memory when actually used. In this case your functions can use the data, but it would also be available to the users.Alternatively, you could make the colors and palettes available as internal data for your functions. This can be done with the same function from {usethis}, the only difference is we set the
internal
argument toTRUE
:usethis::use_data(my_colors, internal = TRUE)
. Now you can refer inside your function to the datamy_palettes
and the function argument can be used to subsetmy_palettes
.
For example:
scale_color_mine(palette = "federal")
would internally do:
scale_color_mine <- function(palette) {
# do stuff here
cur_palette <- my_palettes[[palette]]
# do stuff here
}
In this case the users won't be able to access the data, but the good thing is that my_colors
and my_palettes
wouldn't populate the namespace.
Python: load variables in a dict into namespace
Consider the Bunch
alternative:
class Bunch(object):
def __init__(self, adict):
self.__dict__.update(adict)
so if you have a dictionary d
and want to access (read) its values with the syntax x.foo
instead of the clumsier d['foo']
, just do
x = Bunch(d)
this works both inside and outside functions -- and it's enormously cleaner and safer than injecting d
into globals()
! Remember the last line from the Zen of Python...:
>>> import this
The Zen of Python, by Tim Peters
...
Namespaces are one honking great idea -- let's do more of those!
C++ How do I make a function/variable local to a namespace?
AFAIK there is no access restriction in namespaces in C++.
namespace foo {
void local_func() {}
// local_func can be accessed inside the namespace
void global_func() { local_func(); }
}
// ...
foo::local_func(); // local_func can be accessed outside the namespace
You can achieve something close with static member functions inside a class definition:
class foo {
private:
static void local_func() {}
public:
// local_func can be accessed inside the "namespace" of the class
void global_func() { local_func(); }
};
// ...
foo::local_func(); // error : local_func is private to the class
Change variable in package namespace
The problem seems to have been with the format of the assign statements. Instead of
assign(".myvar", "bar", pos = "package:mypackage")
I used,
assign(".myvar", "bar", pos = asNamespace("mypackage"))
and this resolved the issue.
Injecting variables into an import namespace
I came up with a solution based on this answer and the importlib docs. Basically, I have access to the module object before it is loaded by using the correct sequence of calls to importlib
:
from importlib.util import spec_from_file_location, module_from_spec
from os.path import splitext, basename
def loadConfig(fileName):
test = 'This is a test'
name = splitext(basename(fileName))[0]
spec = spec_from_file_location(name, fileName)
config = module_from_spec(spec)
config.test = test
spec.loader.exec_module(config)
return config
testmod = loadConfig('./testmod.py')
This is a bit better than modifying builtins
, which may have unintended consequences in other parts of the program, and may also restrict the names I can pass in to the module.
I decided to put all the configuration items into a single field accessible at load time, which I named config
. This allows me to do the following in testmod
:
if 'test' in config:
x = config['test']
The loader now looks like this:
from importlib.util import spec_from_file_location, module_from_spec
from os.path import splitext, basename
def loadConfig(fileName, **kwargs):
name = splitext(basename(fileName))[0]
spec = spec_from_file_location(name, fileName)
config = module_from_spec(spec)
config.config = kwargs
spec.loader.exec_module(config)
return config
testmod = loadConfig('./testmod.py', test='This is a test')
After finding myself using this a bunch of times, I finally ended up adding this functionality to the utility library I maintain, haggis
. haggis.load.load_module
loads a text file as a module with injection, while haggis.load.module_as_dict
does a more advanced version of the same that loads it as a potentially nested configuration file into a dict
.
Accessing a global and namespace variable
Let's start with another example.
const int x = 10;
namespace e {
const int y = 5;
}
int main()
{
std::cout << e::y;
using namespace e;
std::cout << y;
}
There is variable with value 10 and name x
in global namespace (which can be referred to as x
simply) and variable with value 5 with name y
in namespace e
(which must be referred to as e::y
).
By adding using namespace e;
, you inject all names from namespace e
into global namespace. This means global namespace now contains names x
and y
, and namespace e
contains name y
. You can now refer to variable with value 5
using both y
and e::y
.
Now, back to your example. If we change y
to x
:
const int x = 10;
namespace e {
const int x = 5;
}
int main()
{
std::cout << e::x;
using namespace e;
std::cout << x;
}
There is x
in global namespace and x
in namespace e
. By adding using namespace e;
you inject all the names from namespace e
to global namespace, so now global namespace contains names x
and x
, and namespace e
contains name x
. See the problem? Global namespace contains two names x
, which confuses the compiler. When you try to print variable under the name x
, compiler looks up names in global namespace and finds two x
. It cannot choose which one you meant, so it throws error.
This is the main reason why using namespace
(particularly using namespace std;
) is considered evil. One can easily break working code by updating a library or introducing a new function. Compiler error is best outcome in such a case, but sometimes it's possible that compiler will silently replace one function by another, because it matches better.
You can still access both variables using fully qualified names:
int main()
{
using namespace e;
std::cout << ::x << " "; //x from global with fully quafilied name
std::cout << ::e::x << " "; //x from namespace e with fully qualified name
std::cout << e::x; //not fully qualified, but not ambiguous either - only one x in namespace e
}
How do you access a procedure's local variables in a namespace eval {} inside that same procedure?
You can just use set
with a fully qualified variable name that uses the desired namespace:
proc getNS {name} {
namespace eval ns::$name {} ;# Create namespace if it doesn't already exist
set ns::${name}::n $name
}
getNS foo
puts $ns::foo::n ;# foo
Another way is to use uplevel
to refer to the scope of the proc that calls namespace eval
:
proc getNS {name} {
namespace eval ns::$name {
set n [uplevel 1 {set name}]
}
}
Related Topics
Labelling Logarithmic Scale Display in R
How to Replace Numeric Codes with Value Labels from a Lookup Table
Voronoi Diagram Polygons Enclosed in Geographic Borders
R/Quantmod: Multiple Charts All Using the Same Y-Axis
Shading Confidence Intervals Manually with Ggplot2
Extract Column Name in Mutate_If Call
Changing Word Template for Knitr in Rmarkdown
How to Find the First and Last Occurrences of an Element in a Data.Frame
Frequency Table with Several Variables in R
Stacked Histograms Like in Flow Cytometry
How to Manually Set Geom_Bar Fill Color in Ggplot
R: Split Elements of a List into Sublists
The Art of R Programming:Where Else Could I Find the Information
Add Missing Xts/Zoo Data with Linear Interpolation in R
Porting Set Operations from R's Data Frames to Data Tables: How to Identify Duplicated Rows