Да, это правильный путь.Это может окупиться, чтобы понять некоторые внутренние механизмы пакета.Контексты 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
, чтобы обеспечить какой-то нестандартный способ синтаксического анализа символов и, следовательно, контролировать инкапсуляцию в масштабе пакета некоторым «нестандартным» способом.Я не поощряю это, просто упомяну, чтобы подчеркнуть, что механизм на самом деле намного проще и гораздо более управляем, чем может показаться на первый взгляд.