I had something like the following in my notebook.
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests={"test1", "test2"}
ToExpression[#][5] & /@ tests
When I put this code in a package it doesn't work because test1
is now called MyPackage'Private'test1
. How can I modify the last line to make this code run both inside package and inside notebook?
Update Here's why I was doing doing ToExpression as opposed to using Symbols. In retrospect, maybe it's easier to use Symbols instead
I had a function which I call like getGraphs["LeafFree","Planar",!"Tree",...]
to get all graphs that are leaf free, planar and not trees. Some of those strings are classes in GraphData
, while others were my own classes. For each of my own classes I had a function with identical name, like LeafFree
that tested the property. In the notebook, using ToExpression
code like above was the quickest way to implement this.
getGraphs[n_Integer, cl__] := getGraphs[{n, n}, cl];
getGraphs[{nmin_Integer, nmax_Integer}, cl__] :=
Module[{maxgraphnum = 100},
customClasses = {"isLeafFree", ! "isLeafFree"};
classes = {cl}\[Backslash]customClasses;
builtinClasses =
GraphData["Classes"] \[Tilde] (Not /@ GraphData["Classes"]);
Assert[classes \[Subset] builtinClasses];
isLeafFree[gname_] :=
FreeQ[GraphData[gname, "DegreeSequence"], 0 | 1];
posClasses = Cases[classes\[Backslash]customClasses, _String];
posGroup =
If[posClasses == {}, GraphData[nmin ;; nmax],
GraphData[posClasses, nmin ;; nmax]];
negClasses = classes\[Backslash]posClasses;
negGroups = GraphData[#[[1]], nmin ;; nmax] & /@ negClasses;
result = Complement[posGroup, Sequence @@ negGroups];
customTest[g_] :=
And @@ (ToExpression[#][g] & /@ ({cl} \[Intersection]
customClasses));
(*result=Take[result,Min[Length[result],100]];*)
result = Select[result, customTest]
]
ToExpression
uses the current binding of$Context
when creating symbols, so you can force your expression to be interpreted within a particular context thus:I'm not sure I understand the circumstances of the original question. You can get the current context using
$Context
orContext[]
... butToExpression
will automatically use the current context without intervention.If I run the exhibited code in a notebook, it works fine. If I run it like this:
... it also works fine. I can get it to fail if I run it like this:
... which not only fails but also creates spurious symbols in the notebook's context. You can work around this problem using the
Block
recipe from above.If you want to capture the context that was in effect at the moment the package code was loaded, you can do something like this:
runTests
usesWith
to inject the private package context into its definition.As Janus' noted, it is better to use symbols than strings since they automatically manage the whole context issue -- but this assumes your actual use case will permit the use of symbols.
I agree with the comments above that you should perhaps have a compelling reason to do this, but here goes. Here is a code I use in such cases, which allows your symbol to be parsed in whatever context you like, at run-time:
You can use options to specify some contexts where these symbols exist, that you want to import during the parse stage. You can call this from any package or notebook, and the symbol will be parsed according to whatever context you specify.
HTH
Edit:
Responding to a comment (since it made the question more specific): There is no question that at run-time
Context[]
will display whatever is the current context from where the function was called (Global in that case). I meant something else:Context
has a syntaxContext[symbol]
, to give a context of any symbol if it is on the$ContextPath
. For example,Context[getGraphs]
returnsBulatov'showGraphs'
. Therefore, if you need to determine the context of some exported function automatically, you callContext[function]
. You can use this to construct full names of other (private) functions of that package. Here is a self - contained example:where
x,y
are just some sample arguments. Then, you never actually supply the last argument, but you can use thecontext
variable inside your function, to construct long names for your other functions, as in the sample code above. Or you could just plain use Context[f] inside body of the function, and not add any arguments to it.