2011-02-27 33 views
5

我不知道如何定义私有函数。 当我在写一个包数学,我只是这样做:在mathematica包中定义私有函数

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

这是正确的做法还是我失去了一些东西?

回答

12

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

不管怎么说,什么BeginPackage做的是,它只是替换$ contextPath中的只有{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进行一些“自定义”操作,以确保一些非标准的符号解析方式,并因此以某种“非标准”方式控制封装规模封装。我不鼓励这一点,只是提到要强调这一机制实际上比表面上看起来更简单和更可控。

+0

谢谢您的详尽答复。这有很大帮助。 我问过这个问题,因为我试图从公共的一些函数声明到我的代码的私有“部分”,然后重新上传我测试软件包的笔记本中的包导入语句。那么,与这些函数相对应的名字就变成了红色,但我仍然可以运行这些函数,就好像它们没有变成私有的一样。 –

+0

我还注意到,mathematica(版本7)有时会与当前导入的软件包混淆。例如,我想创建一个完全相同的包,但是在代码中全部都是调试打印。所以我拿了原来的软件包,把名字改成了顶部,然后把它保存为一个不同的软件包。那么,mathematica开始抱怨我有两个相同函数的定义。为什么会这么麻烦? –

+1

它在我看来像你在修改你的代码时没有清除旧的定义。例如,如果您将符号从“foo'”移动到“foo'private”并重新加载包,则当Mathematica解析foo'private中的定义时,它会检测与foo'中已经定义的符号的冲突,并提醒您。所以,你可能想做一些像'ClearAll [“foo \'*”];删除[“foo \'*”]'重新加载修改后的软件包foo时。 –

相关问题