从Package中获取当前上下文

时间:2011-01-28 04:34:03

标签: wolfram-mathematica

我的笔记本中有以下内容。

test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests={"test1", "test2"}
ToExpression[#][5] & /@ tests

当我将此代码放入包中时,它不起作用,因为test1现在称为MyPackage'Private'test1。如何修改最后一行以使此代码在包内和笔记本内部运行?

更新的 这就是为什么我在做ToExpression而不是使用符号。回想起来,也许更容易使用符号

我有一个我称之为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]
  ]

2 个答案:

答案 0 :(得分:4)

ToExpression在创建符号时使用$Context的当前绑定,因此您可以强制在特定上下文中解释表达式:

Block[{$Context="MyPackage`Private`"}, ToExpression[#][5]] & /@ tests

我不确定我是否了解原始问题的情况。您可以使用$ContextContext[]获取当前上下文...但ToExpression将自动使用当前上下文而无需干预。

如果我在笔记本中运行展示的代码,它可以正常工作。如果我像这样运行它:

Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests = {"test1", "test2"}
ToExpression[#][5] & /@ tests
End[]

......它也可以正常工作。如果我像这样运行它,我可以让它失败:

(* in the package file *)
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
End[]

(* in the notebook *)
tests = {"test1", "test2"}
ToExpression[#][5] & /@ tests

...不仅失败了,而且还在笔记本的上下文中创建了虚假的符号。您可以使用上面的Block配方解决此问题。

如果要捕获加载包代码时生效的上下文,可以执行以下操作:

(* in the package *)
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests = {"test1", "test2"};
With[{context = $Context},
  runTests[] := Block[{$Context = context}, ToExpression[#][5]] & /@ tests
]
End[]

(* in the notebook *)
MyPackage`Private`runTests[]

runTests使用With将私有包上下文注入其定义。

正如Janus所说,最好使用符号而不是字符串,因为它们会自动管理整个上下文问题 - 但这假设您的实际用例允许使用符号。

答案 1 :(得分:3)

我同意上面的评论,你应该有一个令人信服的理由去做,但是这里有。这是我在这种情况下使用的代码,它允许在运行时在任何你喜欢的上下文中解析你的符号:

SetAttributes[ParseTimeNameSpaceWrapper,HoldFirst];
Options[ParseTimeNameSpaceWrapper] = {
  LocalizingContext->"MyLocalizingContext`",
  DefaultImportedContexts:>{"Imported1`", "Imported2`"},
  ExtraImportedContexts:>   {}
};



ParseTimeNameSpaceWrapper[code_,opts:OptionsPattern[]]:=
Module[{result,
  context = OptionValue[LocalizingContext],
  defcontexts = OptionValue[DefaultImportedContexts],
  extraContexts = OptionValue[ExtraImportedContexts],
  allContexts},
  allContexts = {Sequence@@defcontexts,Sequence@@extraContexts};
  BeginPackage[context,If[allContexts==={},Sequence@@{},allContexts]];      
    result = code;  
  EndPackage[];
  result
]; 

您可以使用选项指定存在这些符号的某些上下文,您希望在解析阶段导入这些符号。您可以从任何包或笔记本中调用它,并根据您指定的任何上下文解析符号。

HTH

编辑:

回应评论(因为它使问题更具体):毫无疑问,在运行时Context[]将显示调用函数的当前上下文(在这种情况下为Global) 。我的意思是其他内容:Context具有语法Context[symbol],以便在$ContextPath上提供任何符号的上下文。例如,Context[getGraphs]会返回Bulatov'showGraphs'。因此,如果您需要自动确定某些导出函数的上下文,请调用Context[function]。您可以使用它来构造该包的其他(私有)函数的全名。这是一个自包含的例子:

In[1]:= 
BeginPackage["MyTest`"]; 
f[x_, y_, context_: Context[f]] :=
  Module[{f1str = "function1", f2str = "function2", f1, f2}, 
    {f1, f2} = ToExpression[context <> "Private`" <> #] & /@ {f1str, f2str};
    f1[x, y];
    f2[x, y];];

Begin["`Private`"];

function1[x_, y_] :=  Print["In function1: arguments are ", x, " , ", y];
function2[x_, y_] :=  Print["In function2: arguments are ", x, " , ", y];

End[]
EndPackage[];

Out[6]= "MyTest`Private`"

In[8]:= f[1, 2]

During evaluation of In[8]:= In function1: arguments are 1 , 2

During evaluation of In[8]:= In function2: arguments are 1 , 2

其中x,y只是一些示例参数。然后,您实际上从未提供最后一个参数,但您可以在函数内使用context变量,为您的其他函数构造长名称,如上面的示例代码所示。或者你可以在函数体内使用Context [f],而不是向它添加任何参数。