在mathematica包中定义私有函数

发布于 2024-10-19 14:45:17 字数 284 浏览 1 评论 0原文

我不确定我是否正确定义了私有函数。 当我编写一个数学包时,我只是这样做:

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

这是正确的方法还是我遗漏了一些东西?

I'm not sure I got how to define private functions right.
When I'm writing a package mathematica, I just do this:

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

Is this the correct way or am I missing something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小情绪 2024-10-26 14:45:17

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

无论如何,BeginPackage 所做的只是用 {youPublicPackageContext, "System'"} 以及您公开导入的可能的其他上下文替换 $ContextPath 的当前值BeginPackage 的第二个可选参数。因此,如果“公共”部分中的所有符号不在“系统”或您导入的其他上下文中,则它们都会被解析到公共上下文中。 EndPackage 的作用是将 $ContextPath 的值恢复到开始加载包之前的值。因此,从技术上讲,使用消息并不是在主上下文中公开符号的唯一方法 - 您也可以简单地键入带有分号的符号,例如 myFunction; (不鼓励这种做法,我只是提到它来澄清机制)。现在,当您输入 Begin["'Private'"] 时,当前上下文将变为 YourContext'Private' (子上下文)。 $ContextPath 未更改。因此,在那里输入的任何符号,如果您的公共包或其他导入的包(即当前位于 $ContextPath 上的上下文)中不存在,都会自动解析为 'Private'< /代码> 子上下文。

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

Yep, that's a correct way. It may pay off to understand some of the internal package mechanics. Mathematica contexts are similar to namespaces in other languages. They can be nested. Every symbol belongs to some context. At any given moment, some context is "current". Whenever a new symbol is created, the system must decide to which context the symbol will belong. This happens at parse-time. The fundamental quantity (variable) here is $ContextPath. It is basically the search path for symbols. It is a list of contexts, and whenever the system sees a new symbol, it tests if the symbol with the same short name (that is, the name of the symbol proper, without the context) exists in some context on the $ContextPath. If it does exist, then the given occurrence of the symbol will be associated with that existing one. If it does not, then the symbol is created in a current context. Note that this is a dynamic thing - if you change the $ContextPath at any moment, the next symbol occurrence can be associated with a different symbol.

Anyways, what BeginPackage does is that it simply replaces the current value of $ContextPath with just {youPublicPackageContext, "System'"}, plus possibly additional contexts that you publicly import through the second optional argument of BeginPackage. Therefore, all symbols that are in the "public" section, are parsed into the public context, if they are not in "System'" or other contexts that you import. And what EndPackage does is to restore the value of the $ContextPath to what it was before you started loading the package. So, technically the usage message is not the only way to make a symbol public in your main context - you could just as well simply type a symbol with a semicolon, like myFunction; (this practice is discouraged, I just mentioned it to clarify the mechanism). Now, what happens when you enter Begin["'Private'"] is that the current context becomes YourContext'Private' (a sub-context). The $ContextPath is not changed. Therefore, any symbol entered there, which does not exist in your public package or other imported packages (that is, contexts currently on the $ContextPath), automatically is parsed into the 'Private' subcontext.

What really makes these symbols private is that whenever you import your package into some other context (package), only the main package is added to the $ContextPath, but not its sub-packages. Technically, you can break encapsulation by manually adding YourPackage'Private' to the $ContextPath (say, PrependTo[$ContextPath, YourPackage'Private']), and then all your private functions and other symbols will become public in that particular context where you do the import. Again, this practice is discouraged, but it explains the mechanics. The bottom line is that the notion of private or public can be entirely understood when we know how symbols are parsed, and what are the manipulations with $ContextPath and $Context (another system variable giving the value of the current context), that are performed by commands such as Begin and BeginPackage. To put it another way, one could, in principle, emulate the actions of BeginPackage,Begin, End and EndPackage with a user-defined code. There are just a few principles operating here (which I tried to outline above), and the mechanism itself is in fact very much exposed to the user, so that if, in some rare cases, one may want some other behavior, one can make some "custom" manipulations with $ContextPath and Context, to ensure some non-standard way of symbol parsing and therefore, control package-scale encapsulation in some "non-standard" way. I am not encouraging this, just mentioning to emphasize that the mechanism is in fact much simpler and much more controllable than it may seem on the surface.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文