【问题标题】:Is there anything like Python's `if __name__ == "__main__":` stuff in Common Lisp在 Common Lisp 中有没有类似 Python 的 `if __name__ == "__main__":` 的东西
【发布时间】:2012-01-03 14:16:30
【问题描述】:

我在两个单独的文件中编写了两个函数,假设是文件 A.lisp 和 B.lisp,这两个文件都有一些用于测试的主程序代码,A.lisp 会调用 B.lisp 中的函数。这意味着直接在 A.lisp 中使用 load 方法将执行 B.lisp 中的主代码,这是不应该发生的。在我看来,这些文件太小了,无法考虑使用类似 package 的东西。

Common Lisp 中有没有类似 Python 的 if __name__ == "__main__": 的东西?仅当当前文件是主模块(即正在运行的程序)时,才会执行包含在此条件中的顶级代码,但如果它作为库导入则不会执行。

【问题讨论】:

  • 我问的是a similar question about Clojure,而不是 Common Lisp,但您可能会发现一些回答很有帮助,尤其是目前评价最高的回答。
  • 谢谢你,蒂姆!真的很有帮助。

标签: lisp common-lisp


【解决方案1】:

包只是符号的命名空间。他们没有提及加载或编译代码。

Common Lisp 在其 ANSI Common Lisp 标准中没有库、模块甚至类似“主”模块/例程的概念。该标准定义了两个例程PROVIDEREQUIRE。但这些都不是很明确。

大多数应用程序和库使用“系统”工具来构建、指定、编译和加载代码。

有一个名为ASDF 的“免费”。 “另一个系统定义工具”。对于大多数类型的应用程序,像 ASDF 这样的工具很有用。对于原始应用程序,您可以使用COMPILE-FILELOAD等标准函数编写自己的工具。

Nick Levine 为 ASDF 写了一个教程(他放弃的 Lisp 图书项目的一部分):Systems

一些 Lisp 实现具有更广泛的工具来创建应用程序(例如使用 Clozure Common Lisp 编写的 Mac OS X 应用程序)。

【讨论】:

    【解决方案2】:

    if __name__ == "__main__": 成语是 Python 特有的,甚至 Python 社区中的一些人也考虑将其用于测试代码的不良风格。

    由于 Common Lisp 高度重视 REPL 中的交互式开发,因此每次要运行测试时都必须重新加载整个文件实际上是不利的。只需将测试放入函数定义而不是顶层,它就可以工作并且更方便。

    【讨论】:

    • 所以没有办法编写仅在我使用clisp myfile.lisp 而不是(load 'myfile) 运行文件时执行的代码?
    • 您可以将只希望在将文件作为脚本运行时评估的代码放入您在评估脚本时从命令行调用的特殊函数中。我只安装了 SBCL 而不是 CLISP,所以我无法测试你需要如何使用 CLISP 来执行此操作,使用 SBCL 你可以使用sbcl --noinform --load myfile.lisp --eval '(main)' --quit,这当然比你可以使用的sbcl --script myfile.lisp 长很多当代码位于顶层时执行。因此,更简单的方法是让脚本成为加载库部分的额外文件。
    【解决方案3】:

    评估顶级表单。

    你可以像下面的例子那样定义一个主函数,你可以随意调用这个函数:

    a.lisp

    (defun main ()
      ...)

    b.lisp

    (load "a.lisp")
    (main)

    【讨论】:

    • 但是如果我有时想单独运行 A.lisp 进行一些测试工作怎么办?
    • 但是如果我想单独执行它,我必须能够执行 A.lisp 中的 main 函数。如果main的函数调用只存在于B.lisp中怎么办?
    • 为每个运行所需测试的 .lisp 文件创建一个特定函数还不够,例如 run-a-testsrun -b-tests 然后你从 REPL 调用那个函数?或者您是从 shell 中将其作为脚本运行?
    • 从 shell 中以脚本的形式运行是一种非常正常的操作模式。如果我有一些代码作为执行文件的“主要”动作运行,只告诉 lisp 运行该文件很方便,但如果我想在 REPL 中调试,能够加载文件很方便不执行“主要”动作。将这两个东西放在一起并使用if __name__ == '__main__': 之类的东西比创建第二个文件来加载第一个文件并激活“主要”操作要方便得多。
    【解决方案4】:

    我真的不知道它在 Python 中是如何工作的,但它看起来像一个文件 一个模块,两个文件是两个不同的模块。情况并非如此 常见的 Lisp。如果你没有定义任何包,当你load一个文件时, 所有定义都将在当前包中可用(CL-USER 是 默认)。这更像是您将代码粘贴到 REPL 中。

    但是包并不难使用。

    在 A.lisp 中:

    (defpackage foo
      (:use #:cl)
      (:export main))
    
    (in-package :foo)
    
    (defun main ()
       (do-some-stuff)
       (baz:main some-args))
    

    在 B.lisp 中:

    (defpackage baz
      (:use #:cl)
      (:export main))
    
    (in-package :baz)
    
    (defun main (some-args)
       (do-some-stuff))
    

    你可以阅读 The Complete Idiot's Guide to Common Lisp PackagesPCL chapter on packages.

    【讨论】:

      猜你喜欢
      • 2010-09-15
      • 2016-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-19
      • 1970-01-01
      • 2015-04-04
      • 2020-03-11
      相关资源
      最近更新 更多