Получение текущего контекста из пакета - PullRequest
2 голосов
/ 28 января 2011

У меня было что-то вроде следующего в моей записной книжке.

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 ]

4 голосов
/ 28 января 2011

ToExpression использует текущую привязку $Context при создании символов, поэтому вы можете принудительно интерпретировать свое выражение в определенном контексте следующим образом:

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

Я не уверен, что понимаю обстоятельства первоначального вопроса. Вы можете получить текущий контекст, используя $Context или Context[] ..., но 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 для вставки контекста частного пакета в его определение.

Как отметил Янус, лучше использовать символы, чем строки, поскольку они автоматически решают проблему всего контекста, но это предполагает, что ваш фактический вариант использования позволит использовать символы.

3 голосов
/ 28 января 2011

Я согласен с комментариями выше, что у вас может быть веская причина для этого, но здесь идет.Вот код, который я использую в таких случаях, который позволяет анализировать ваш символ в любом контексте, который вам нравится, во время выполнения:

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] внутри тела функции и не добавлять к ней никаких аргументов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...