在许多编程语言中,例如 Python,要使用函数,我们应该明确声明函数名称和包含该函数的包。然而,在 Latex 中,当我们使用时\usepackage{<package-name>}
,它会从包中导入所有命令(宏),因此我们无法控制导入哪些命令,因此,我们通常会得到以下错误:一个命令的多个定义。
有没有办法明确导入某个命令而不是使用包中的所有命令?
答案1
从使用 Python 和 TeX 编程的人的角度来回答。
在 Python 中,默认情况下,如果一个包执行类似以下操作
def f():
pass
def g():
f()
函数f
和g
在“全局”命名空间中定义,但它不是“真正的全局”,而只是“模块全局”,因此它不会干扰导入它的代码。
如果您这样做from my_module import g
,那么当g
被调用并且它尝试调用时,会在模块的全局变量中查找f
名称,而这并不要求它本身在导入代码的全局变量中可用。f
my_module
f
然而在 TeX 中,默认情况下所有内容都处于真正的全局范围内;此外,默认情况下所有名称都在全局范围内查找。
类似地,Python 有一个“真正的全局变量”,即builtins
模块,该模块的变量可供每个模块使用。在这种情况下,上述代码片段的 TeX 等效代码将是
import builtins
def f():
pass
builtins.f=f
def g():
builtins.f()
builtins.g=g
在这种情况下,即使你将 复制g
到其他名称,为了使其正常工作,命名的全局函数必须f
是f
这个模块。
这解释了当您尝试导入两个具有名为f
和 的函数的不同模块时遇到的困难g
。
从 TeX 的角度来看,上面的内容等同于
\cs_new_protected:Npn \__mymodule_f: {
}
\cs_new_protected:Npn \__mymodule_g: {
\__mymodule_f:
}
那么将使\usepackage{mymodule}
名称分别可用作和\__mymodule_f:
,\__mymodule_g:
并且的等效项from mymodule import f
将是上面的加上\cs_new_eq:NN \f \__mymodule_f:
。
不用说,大多数用户级模块都不是这样实现的,因为典型的用户不知道这\cs_new_eq:NN
是什么。
(虽然公平地说仍然可以创建一个命令,\importFromMymodule \f
即明确定义\f
等等\importAllFromMymodule
。但通常没人需要这些东西)
尽管如此,如果你真的坚持的话,大多数时候“命令杂耍”可以通过
\usepackage{first package that defines f}
\NewCommandCopy \firstPackageF \f % optional, if you want to call the first package's \f
\let \f \undefined % delete the first package's \f so the second package can define it -- as explained above any "\g" in the first package might cease to work
\usepackage{second package that defines f}
对于“实施良好”的软件包来说,这应该基本可以起作用。
在极少数情况下,不需要这样做,在调用旧包的函数之前,需要恢复隐藏包的所有名称。
答案2
举例来说,假设你只想\qty
从导入siunitx
。定义很容易找到,即
8244 \NewDocumentCommand \qty { O { } m > { \TrimSpaces } m }
8245 {
8246 \mode_leave_vertical:
8247 \group_begin:
8248 \siunitx_unit_options_apply:n {#3}
8249 \keys_set:nn { siunitx } {#1}
8250 \siunitx_quantity:nn {#2} {#3}
8251 \group_end:
8252 }
(添加了行号以供参考)。您是否可以考虑将此定义复制到文件中,也许更改名称,以及\qty
(或您选择的命令名称)以按预期工作?
抱歉,不是。这个定义只是冰山一角,它依赖于它前面的几乎所有 8243 行。永远不要将 TeX 与其他编程语言进行比较:例如,它没有命名空间的概念,尽管好的包编程会模拟它。
我相信,当你从 Python 包中加载特定函数时,Python 本身能够猜测它必须从包中加载哪些辅助函数,但这在 TeX 中基本上是不可能的。
如果在加载两个包时发现名称冲突,则可以通过重命名和调整来解决问题。但这并不总是可行的。如果您喜欢 中的某个功能,但algorithm2e
在 中却不存在algpseudocode
,那么将它们混合起来就相当困难(如果可能的话);您可以尝试algpseudocode
使用此包的功能和基础结构重新实现 中的该功能。
顺便说一句,如果你在包中寻找某个命令的定义,很可能你不会找到它。