【问题标题】:Define private function in a mathematica package在数学包中定义私有函数
【发布时间】:2011-02-27 19:57:47
【问题描述】:

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

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

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

【问题讨论】:

    标签: package wolfram-mathematica private-functions


    【解决方案1】:

    是的,这是正确的方法。了解一些内部包机制可能会有所收获。 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 等命令执行。换句话说,原则上可以用用户定义的代码模拟BeginPackageBeginEndEndPackage 的动作。这里只有一些原则(我试图在上面概述),而且机制本身实际上是非常暴露给用户的,所以如果在极少数情况下,一个人可能想要一些其他行为,一个人可以做出使用$ContextPathContext 进行一些“自定义”操作,以确保某些非标准的符号解析方式,从而以某种“非标准”方式控制包规模封装。我不鼓励这样做,只是强调该机制实际上比表面上看起来要简单得多,可控得多。

    【讨论】:

    • 感谢您详尽的回复。这有很大帮助。我问这个问题是因为我尝试将一些函数声明从公共的公共“部分”放入我的代码的私有“部分”,然后在我测试包的笔记本中重新上传包导入语句。好吧,那些函数对应的名字变成了红色,但我仍然可以运行这些函数,就好像它们没有变成私有函数一样。
    • 我还注意到,mathematica(版本 7)有时会与当前导入的包混淆。例如,我想创建完全相同的包,但在整个代码中都带有调试打印。于是我拿了原来的包,把上面的名字改了,另存为不同的包。好吧,mathematica 然后开始抱怨我对相同的函数有两个定义。为什么会打扰?
    • 在我看来,您在修改代码时并未清除旧定义。例如,如果您从“foo" to "fooprivate”中移动符号并重新加载包,当 Mathematica 解析 fooprivate it detects the conflicts with already-defined symbols in foo 中的定义并提醒您时。所以,在重新加载修改后的包 foo 时,您可能想要执行类似 ClearAll["foo`*"]; Remove["foo`*"] 的操作。
    • @Ricky:您所指的“影子”消息并不意味着通常意义上的“定义冲突”。这只是意味着在 $ContextPath 的当前设置下,一些短符号不能唯一解析。看到这个答案:stackoverflow.com/questions/4988815#4988815
    • @Ricky 我前段时间写了一个包,叫做PackageManipulations,它有一个函数PackageReload 和一些其他的函数,允许以干净的方式重新加载一个修改过的包。还有一个选项KillShadowing,如果设置为True,将Remove$ContextPath上其他包的冲突符号。通常,这是处理阴影的“硬”方式。更温和的方法是暂时从 $ContextPath 中删除冲突的上下文。无论如何,包裹位于mathprogramming-intro.org/additional_resources.html
    猜你喜欢
    • 2013-08-27
    • 1970-01-01
    • 2016-09-03
    • 2017-08-20
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 2015-03-14
    相关资源
    最近更新 更多