6

我不确定我是否知道如何正确定义私有函数。当我写一个包mathematica时,我只是这样做:

BeginPackage["myPackage`"]
myPublicFunction::usage="myPublicFunction blahblahblah";
Begin["Private"]
myPrivateFunction[input_]:= ... ;
myPublicFunction[input_]:= ... ;
End[]
EndPackage[]

这是正确的方法还是我错过了什么?

4

1 回答 1

13

是的,这是正确的方法。了解一些内部包机制可能会有所收获。Mathematica 上下文类似于其他语言中的名称空间。它们可以嵌套。每个符号都属于某个上下文。在任何给定时刻,某些上下文是“当前的”。每当创建一个新符号时,系统必须决定该符号属于哪个上下文。这发生在解析时。这里的基本量(变量)是$ContextPath。它基本上是符号的搜索路径。它是一个上下文列表,每当系统看到一个新符号时,它都会测试具有相同短名称(即符号本身的名称,没有上下文)的符号是否存在于某个上下文中$ContextPath. 如果它确实存在,那么给定的符号将与现有的符号相关联。如果不是,则在当前上下文中创建符号。请注意,这是一个动态的事情 - 如果您随时更改$ContextPath,下一个符号出现可以与不同的符号相关联。

无论如何,BeginPackage它只是简单地将 $ContextPath 的当前值替换为 just {youPublicPackageContext, "System'"},加上您通过 . 的第二个可选参数公开导入的可能的其他上下文BeginPackage。因此,“公共”部分中的所有符号都将被解析到公共上下文中,如果它们不在“系统”或您导入的其他上下文中。所做EndPackage的是将 的值恢复$ContextPath到开始加载包之前的值。因此,从技术上讲,使用消息并不是在主要上下文中公开符号的唯一方法 - 您也可以简单地键入带有分号的符号,例如myFunction;(不鼓励这种做法,我只是为了阐明机制而提到它) . 现在,当你进入时会发生什么Begin["'Private'"]是当前上下文变成YourContext'Private'(一个子上下文)。$ContextPath没有改变。因此,在此处输入的任何符号,不存在于您的公共包或其他导入的包(即当前位于 上的上下文$ContextPath)中,都会自动解析到'Private'子上下文中。

真正使这些符号私有的是,每当您将包导入其他上下文(包)时,只有主包被添加到 . $ContextPath,而不是它的子包。从技术上讲,您可以通过手动添加YourPackage'Private'到 $ContextPath(例如,PrependTo[$ContextPath, YourPackage'Private'])来打破封装,然后您的所有私有函数和其他符号将在您执行导入的特定上下文中公开。同样,不鼓励这种做法,但它解释了机制。底线是,当我们知道符号是如何解析的,以及使用$ContextPath$Context(另一个系统变量给出当前上下文的值)的操作是什么时,可以完全理解私有或公共的概念,这些操作由以下命令执行:BeginBeginPackage. 换句话说,原则上可以使用用户定义的代码来模拟、 和的BeginPackage动作Begin。这里只有几个原则(我试图在上面概述),而且机制本身实际上是非常暴露给用户的,所以如果在极少数情况下,一个人可能想要一些其他行为,一个人可以做出使用和进行一些“自定义”操作,以确保某些非标准的符号解析方式,因此以某种“非标准”方式控制包规模封装。我不鼓励这样做,只是强调该机制实际上比表面上看起来要简单得多,可控得多。EndEndPackage$ContextPathContext

于 2011-02-27T21:01:01.210 回答