Определить частную функцию в пакете Mathematica
Я не уверен, что понял, как правильно определять частные функции. Когда я пишу пакет Mathematica, я просто делаю это:
BeginPackage["myPackage`"]
myPublicFunction::usage="myPublicFunction blahblahblah";
Begin["Private"]
myPrivateFunction[input_]:= ... ;
myPublicFunction[input_]:= ... ;
End[]
EndPackage[]
Это правильный путь или я что-то упустил?
1 ответ
Да, это правильный путь. Это может окупиться, чтобы понять некоторые внутренние механизмы пакета. Контексты Mathematica похожи на пространства имен в других языках. Они могут быть вложенными. Каждый символ принадлежит некоторому контексту. В любой момент некоторый контекст является "текущим". Всякий раз, когда создается новый символ, система должна решить, к какому контексту будет принадлежать символ. Это происходит в разбор времени. Основная величина (переменная) здесь $ContextPath
, Это в основном путь поиска символов. Это список контекстов, и всякий раз, когда система видит новый символ, она проверяет, существует ли символ с таким же коротким именем (то есть именем самого символа без контекста) в некотором контексте на $ContextPath
, Если он существует, то данное вхождение символа будет связано с существующим. Если это не так, то символ создается в текущем контексте. Обратите внимание, что это динамическая вещь - если вы измените $ContextPath
в любой момент следующее вхождение символа может быть связано с другим символом.
В любом случае, что BeginPackage
делает то, что он просто заменяет текущее значение $ContextPath просто {youPublicPackageContext, "System'"}
плюс, возможно, дополнительные контексты, которые вы публично импортируете через второй необязательный аргумент BeginPackage
, Поэтому все символы, которые находятся в разделе "public", анализируются в общедоступном контексте, если они не находятся в "System" или других контекстах, которые вы импортируете. И что EndPackage
делает, чтобы восстановить значение $ContextPath
до того, что было до того, как вы начали загружать пакет. Таким образом, технически сообщение об использовании не является единственным способом сделать символ общедоступным в вашем основном контексте - вы можете просто ввести символ с точкой с запятой, например myFunction;
(эта практика не рекомендуется, я только что упомянул ее, чтобы прояснить механизм). Теперь, что происходит, когда вы входите Begin["'Private'"]
является то, что текущий контекст становится YourContext'Private'
(под-контекст). $ContextPath
не изменился. Поэтому любой введенный символ, которого нет в вашем общедоступном пакете или других импортированных пакетах (то есть контексты, которые в настоящее время находятся в $ContextPath
), автоматически разбирается в 'Private'
подконтекст.
Что действительно делает эти символы закрытыми, так это то, что всякий раз, когда вы импортируете свой пакет в какой-то другой контекст (пакет), в него добавляется только основной пакет. $ContextPath
, но не его подпакеты. Технически, вы можете нарушить инкапсуляцию, добавив вручную YourPackage'Private'
в $ContextPath (скажем, PrependTo[$ContextPath, YourPackage'Private']
), и тогда все ваши личные функции и другие символы станут общедоступными в том конкретном контексте, в котором вы выполняете импорт. Опять же, эта практика не рекомендуется, но она объясняет механику. Суть в том, что понятие частного или публичного может быть полностью понято, когда мы знаем, как анализируются символы, и каковы манипуляции с $ContextPath
а также $Context
(другая системная переменная, задающая значение текущего контекста), которые выполняются такими командами, как Begin
а также BeginPackage
, Иными словами, в принципе можно подражать действиям BeginPackage
,Begin
, End
а также EndPackage
с пользовательским кодом. Здесь действуют всего несколько принципов (которые я попытался обрисовать выше), и сам механизм на самом деле очень открыт для пользователя, так что если в некоторых редких случаях кому-то может понадобиться другое поведение, можно некоторые "нестандартные" манипуляции с $ContextPath
а также Context
, чтобы обеспечить какой-то нестандартный способ синтаксического анализа символов и, следовательно, контролировать инкапсуляцию в масштабе пакета некоторым "нестандартным" способом. Я не поощряю это, просто упомяну, чтобы подчеркнуть, что механизм на самом деле намного проще и гораздо более управляем, чем может показаться на первый взгляд.