我不确定我如何正确定义私有(private)函数。
当我写一个数学包时,我只是这样做:
BeginPackage["myPackage`"]
myPublicFunction::usage="myPublicFunction blahblahblah";
Begin["Private"]
myPrivateFunction[input_]:= ... ;
myPublicFunction[input_]:= ... ;
End[]
EndPackage[]
这是正确的方法还是我错过了什么?
最佳答案
是的,这是正确的方法。了解一些内部封装机制可能会有所返回。 Mathematica上下文类似于其他语言中的 namespace 。它们可以嵌套。每个符号都属于某个上下文。在任何给定时刻,某些上下文都是“当前的”。每当创建新符号时,系统都必须确定该符号将属于哪个上下文。这是在解析时发生的。这里的基本数量(变量)是$ContextPath
。它基本上是符号的搜索路径。它是上下文的列表,每当系统看到一个新符号时,它都会测试$ContextPath
上某个上下文中是否存在具有相同短名称(即,没有上下文的正确符号名称)的符号。如果确实存在,则给定的符号出现将与现有符号相关联。如果不是,则在当前上下文中创建符号。请注意,这是动态的事情-如果您随时更改$ContextPath
,则下一个出现的符号可能与另一个符号相关联。
无论如何,BeginPackage
所做的是仅用{youPublicPackageContext, "System'"}
替换$ ContextPath的当前值,以及可能通过BeginPackage
的第二个可选参数公开导入的其他上下文。因此,如果“公共(public)”部分中的所有符号都不在“系统”或您导入的其他上下文中,则将被解析到公共(public)上下文中。 EndPackage
所做的是将$ContextPath
的值恢复为开始加载软件包之前的值。因此,从技术上讲,用法消息不是在主要上下文中公开符号的唯一方法-您也可以简单地用分号键入符号,例如myFunction;
(不鼓励这种做法,我只是提到它来阐明机制)。现在,当您输入Begin["'Private'"]
时会发生什么,就是当前上下文变为YourContext'Private'
(子上下文)。 $ContextPath
不变。因此,在此输入的任何符号(您的公共(public)软件包或其他导入的软件包(即当前在$ContextPath
中的上下文)中不存在的符号)都会自动解析为'Private'
子上下文。
使这些符号私有(private)的真正原因是,每当您将包导入其他上下文(包)时,只会将主包添加到$ContextPath
,而不是其子包。从技术上讲,您可以通过将YourPackage'Private'
手动添加到$ ContextPath(例如PrependTo[$ContextPath, YourPackage'Private']
)来破坏封装,然后所有私有(private)函数和其他符号将在您进行导入的特定上下文中公开。同样,不鼓励这种做法,但可以解释其原理。底线是,当我们知道如何解析符号以及通过命令执行的$ContextPath
和$Context
(另一个提供当前上下文值的系统变量)的操作时,可以完全理解私有(private)或公共(public)的概念。例如Begin
和BeginPackage
。换句话说,原则上可以使用用户定义的代码模拟BeginPackage
,Begin
,End
和EndPackage
的 Action 。这里只运行了几条原则(我在上面曾试图概述过),而该机制本身实际上已经向用户公开了,因此,在极少数情况下,如果人们可能想要某些其他行为,则可以做到这一点。使用$ContextPath
和Context
进行的一些“自定义”操作,以确保某些非标准的符号解析方式,从而以某种“非标准”方式控制程序包规模的封装。我不鼓励这样做,只是要强调指出,该机制实际上比表面上看起来更简单和可控。