从包内获取当前上下文
我的笔记本里有类似以下内容。
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests={"test1", "test2"}
ToExpression[#][5] & /@ tests
当我将此代码放入包中时,它不起作用,因为 test1
现在称为 MyPackage'Private'test1
。如何修改最后一行以使此代码在包内和笔记本内运行?
更新 这就是为什么我使用 ToExpression 而不是使用符号。回想起来,也许使用 Symbols 更容易,
我有一个函数,我称之为 getGraphs["LeafFree","Planar",!"Tree",...] 来获取所有图形无叶、平面而不是树木。其中一些字符串是 GraphData 中的类,而其他字符串是我自己的类。对于我自己的每个类,我都有一个具有相同名称的函数,例如测试属性的 LeafFree
。在笔记本中,使用上面的 ToExpression
代码是实现此目的的最快方法。
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]
]
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]
]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我同意上面的评论,你也许应该有一个令人信服的理由这样做,但这里是。这是我在这种情况下使用的代码,它允许在运行时在您喜欢的任何上下文中解析您的符号:
您可以使用选项来指定这些符号存在的某些上下文,您希望在解析阶段导入这些符号。您可以从任何包或笔记本中调用它,并且该符号将根据您指定的任何上下文进行解析。
HTH
编辑:
回应评论(因为它使问题更加具体):毫无疑问,在运行时
Context[]
将显示调用函数的当前上下文(在这种情况下是全球性的)。我的意思是:Context
有一个语法Context[symbol]
,用于给出任何符号的上下文(如果它位于$ContextPath
上)。例如,Context[getGraphs]
返回Bulatov'showGraphs'
。因此,如果您需要自动确定某些导出函数的上下文,请调用Context[function]
。您可以使用它来构造该包的其他(私有)函数的全名。这是一个独立的示例:其中 x,y 只是一些示例参数。然后,您实际上永远不会提供最后一个参数,但您可以在函数内使用 context 变量,为其他函数构造长名称,如上面的示例代码所示。或者您可以在函数体内简单地使用 Context[f] ,而不向其添加任何参数。
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.ToExpression
在创建符号时使用$Context
的当前绑定,因此您可以强制在特定上下文中解释表达式:我不确定我是否理解情况原来的问题。您可以使用
$Context
或Context[]
获取当前上下文...但ToExpression
将自动使用当前上下文,无需干预。如果我在笔记本中运行展示的代码,它工作得很好。如果我像这样运行它:
...它也工作得很好。如果我像这样运行它,它可能会失败:
...这不仅会失败,还会在笔记本的上下文中创建虚假符号。您可以使用上面的
Block
配方来解决此问题。如果您想捕获加载包代码时有效的上下文,您可以执行以下操作:
runTests
使用With
注入私有包上下文进入其定义。正如 Janus 所指出的,使用符号比使用字符串更好,因为它们会自动管理整个上下文问题 - 但这假设您的实际用例将允许使用符号。
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.