如何正确理解BeginPackage与Begin?
mathematica吧
全部回复
仅看楼主
level 1
_Khattiya_ 楼主
用Get运行以下三个wl:
第一个
BeginPackage["Functions`"]
S1=1;
Begin["Test1`"]
K1=2;
End[]
EndPackage[]
结果只能查询到Functions`S1=1,无论是?Funstions`Test1`K1还是?Test1`K1都查询不到结果,请问这个K1去哪了?
第二个
BeginPackage["Functions`"]
S1=1;
Begin["`Test1`"]
K1=2;
End[]
EndPackage[]
这样能正确查询到Functions`S1=1与Funstions`Test1`K1=2
第三个
BeginPackage["Functions`"]
S1=1;
Begin["`Test1`"]
S1=2;
End[]
EndPackage[]
得到的结果居然是Functions`S1=2,Functions`Test1`S1去哪了?Functions`S1的值为什么会发生改变?Begin在这里起了什么作用?
2020年07月15日 07点07分 1
level 14
有两个概念,$Context和$ContextPath,即当前上下文和上下文搜索路径,符号先从上下文路径搜索,如果上下文路径里没有则在当前上下文创建符号。BeginPackage开始时限制$ContextPath为自己和System`(也可以手动引入其它上下文),而结束后不光会还原$Context,还会把自己的上下文加入$ContextPath中,而Begin系列除了修改$Context之外啥也不干,也就是并不会把这个上下文暴露给外部也不会改变上下文搜索路径。
具体的,
第一个,虽然Begin不把符号暴露给外部,但运行?Test1`K1用全名查询应该是会有的,我这里是可以搜索到的;
第二个,全名查询,没毛病,`开始表示从当前上线文开始的相对上下文(类似相对路径);
第三个,Begin系列,不改变上下文路径,因此之前引入的符号会被直接拿来使用而不会创建新的。
因此,我们往往在BeginPackage和Begin之间引入要公开的符号,而在Begin中书写实现以减少符号冲突。
2020年07月15日 08点07分 2
对第三例的解说中,“因此”一词说法不适当——前后陈述间并无因果关系。就算Test1`处改用BeginPackage,也一样会调用已有的符号。你的意思大概是因为Function`处用了BeginPackage,而不是Begin,所以后文Test1处中的符号短名被补全为已存在的符号名
2020年07月16日 11点07分
@asdasd1dsadsa 好吧,我没说是短名,是我输了[冷]
2020年07月16日 11点07分
@magus000 和短名这个说法没关系。可能令人误解的是“因此”。
2020年07月16日 14点07分
@asdasd1dsadsa 按我的理解,符号短名的解析首先从$ContextPath搜索。Begin不改变$ContextPath所以之前已经在$ContextPath的符号会被搜到,而不创建新的符号;相对的,BeginPackage改变$ContextPath,使之前引入的符号无法搜到,因此会创建新符号。
2020年07月16日 15点07分
level 1
_Khattiya_ 楼主
2020年07月15日 08点07分 3
Test1`K1吧
2020年07月15日 09点07分
@magus000 [笑尿]是我傻了
2020年07月15日 09点07分
level 1
_Khattiya_ 楼主
@magus000 感谢您的解答!不知道为什么不能在层中回复。。。我是一个新手,请问是否能详细介绍一下“在BeginPackage和Begin之间引入要公开的符号”的含义?另外,第一个代码我确实无法用?Test`K1查询到符号信息,我把输出结果贴在楼下
2020年07月15日 09点07分 5
看文档:tutorial/ModularityAndTheNamingOfThings#5934
2020年07月15日 09点07分
这里感觉有点像别的语言了。在begin和beginpackage间是public context,先在这声明接下来你准备的函数名,这些函数才能被用户调用,一般是通过定义usermassage。begin开时候后是private context,在这里定义你刚刚声明的函数。
2020年07月15日 11点07分
@三炮快跑☞ 是否可以不用Begin而直接使用module?或者在Begin之前就定义函数
2020年07月15日 12点07分
@_Khattiya_ 用begin是因为要在private context下,而非像module一样的独立空间里定义函数,所以module应该不行。至于在begin前定义函数感觉似乎可以,但问题可能在于你的这样的扩展包会被用户改来改去,达不到封装的目的。我一会自己试下。
2020年07月15日 18点07分
level 14
@asdasd1dsadsa 用BeginPackage似乎并不会直接用外层的。不过奇妙的是这个shadow,还有点迷惑,明明$ContextPath里是没有Test`的。
2020年07月16日 15点07分 6
我还是第一次注意到这个情况也会shadow,是因为他们都会在前一个EndPackage[]时被导出到外层吗?
2020年07月16日 15点07分
level 14
还是很迷惑啊
2020年07月16日 15点07分 7
找到一个回答, mathematica.stackexchange.com/a/119887/66707 指出"::shdw"消息发生在Append[$ContextPath, $Context]中包含两个一样的符号短名时,而并非实际搜索时使用的$ContextPath。不过还是不知道为啥要这么设计[呼~]
2020年07月16日 15点07分
@magus000 这样啊
2020年07月17日 02点07分
1