【问题标题】:Terminate importation of module non-fatally?非致命地终止模块的导入?
【发布时间】:2011-06-02 16:44:17
【问题描述】:

我想使用if __name__ != '__main__':,然后在导入脚本时结束脚本的执行,而不是像往常一样使用if __name__ == '__main__': 并缩进文件中的所有其余代码。

但是,我无法确定是什么原因只会导致这种情况发生并且不会产生其他不良副作用。 sys.exit() 停止整个解释器,我尝试过的所有其他事情要么引发某种异常,要么是非法的。

更新:

我选择了@trutheality 的答案,因为它实现了我想要的并且非常容易开始使用。也就是说,我认为其他几个答案非常有趣和/或聪明——感谢所有回复的人——并计划在时间允许的情况下进一步调查其中的一些。我不知道做我想做的事会如此投入。

【问题讨论】:

  • 您到底想要发生什么?您是否希望导入成功,但默默地什么都不做?
  • 如果只是为了不缩进其余代码,算了。如果脚本足够大以至于这是一个严重的问题,那么大多数代码无论如何都应该在函数中;)
  • @JasonFruit:是的,我希望导入成功。
  • @martineau:我看不出有什么方法可以在不导入模块名称的情况下做到这一点,尽管您可以将其设为空。真的,如果你尝试导入它,你应该让它引发一个异常,并让导入脚本处理它。看起来成功但没有做任何可以被定义为成功的事情是一个问题。
  • @JasonFruit:我所说的成功是指在此之前模块中定义的所有内容都保持正常 - 这通常似乎排除了引发异常而中止模块加载的情况(除非你这样做在@David 的partialimport 答案中看起来有些险恶)。

标签: python import


【解决方案1】:

另一个黑客:

# code

if __name__ == "__main__": exec("""

# main code

#""")

所以...你已经失去了缩进,还有语法高亮和你正在使用的编辑器的任何其他功能,除非你在每次编辑时注释掉 if 行。

【讨论】:

  • +1 是迄今为止我见过的最干净、最不突兀的答案。
  • @Tadeck:因为它以最少的努力、副作用和维护实现了既定目标。我试图以客观、分析和个案的方式来回应 exec() 的使用,而不是自动下意识地回应。
  • @martineau 这不是我的自动下意识,而是包含粗心使用exec() 类解决方案的代码的经验。 OP 还表示他想要doing the usual if __name__ == '__main__': and indentation of all the rest of the code in the file 以外的解决方案。为什么你认为他更喜欢 IDE 将他的所有代码都视为字符串而不是缩进代码?
  • @martineau 我刚刚意识到你是 OP,因此在假设 OP 的想法和 OP 真正想要/需要的东西时,你实际上可能是正确的;)
  • @Tadeck:没问题。恕我直言,这种使用exec() 是可以接受的。 FWIW,我经常不使用我拥有的 Python IDE,而是更喜欢我多年来使用的相当复杂的文本编辑器 - 但在任何一种情况下(正如编辑的答案现在指出的那样),只需注释掉if 与单个 # 将使 exec() 中的所有代码成为非字符串。事实上,我可以制作一个宏,一键打开和关闭它。
【解决方案2】:

与我最初的答案非常相似,但有点吓人

部分导入.py

class PartialImport(Exception):
    def __init__(self, locals, msg = ""):
        self.module = locals

main.py

from partialimport import PartialImport
try:
   import foo
except PartialImport, e:
    #Note e.module and therefore foo will be a Dict and not a module instance!
    foo = e.module

foo.py

from partialimport import PartialImport

class Boo:
    pass

if __name__ != "__main__":    
    raise PartialImport(locals())

class Foo:
    pass

免责声明

这是一个非常可怕的黑客,会增加你的同伴谋杀你的可能性,但这确实有效。

【讨论】:

  • 不像我希望的那样透明(或可用),但为创造力和低开销+1,你这个邪恶的天才。 ;-)
  • @martineau 老实说,我期待着看看是否有人能找到更好/更优雅的解决方案。
  • 这个我会投赞成票,虽然我不希望任何人实际使用它。更糟糕的是,您实际上可以使用 types.ModuleType 并替换 __import__ 函数,这样您就可以将 foo 作为一个模块。
  • 对不起,但这实际上不起作用,尽管e.module 字典中有 are 条目对应于模块中定义的事物 (foo ,在您的示例中),它们都映射到 None 并且无法使用。我认为这是提出一个例外的结果——也许与this answer 中描述的情况类似,对于另一个问题(但那里的修复不适用于这种情况)。
  • @martineau 太令人失望了,看看我能不能找到另一个开箱即用的解决方案。
【解决方案3】:

main.py

try:
   import foo
except:
    print "Failed to import foo"

foo.py

文件顶部

if __name__ != "__main__":
   raise RunTimeError("foo must be run as main, not as a module.")

class foo(Object):
   pass

由于python是按顺序处理文件的,所以不会定义类Foo。

另一个想法是通过PEP 302 重载导入逻辑本身

【讨论】:

  • 几乎 +1。在导入时捕获任何异常都是不好的做法。 except RunTimeError,请。如果你很挑剔,你会定义自己的异常,所以它不能被其他任何东西引发。
  • 其实我改变了主意。异常中止加载模块,因此您不能在 main.py 中使用任何 foo 模块。
  • 也许我不清楚,我希望导入成功,到此为止。运行模块而不是作为__main__ 执行它很好,并且会继续超出if
  • @Thomas K 我通常不寻求 SO sn-ps 的最佳实践,主要针对的是想法而不是细节,而是使用“Diaper”反模式的生产级代码绝对是在要求口头辱骂;)
  • 对于其他想知道的人,您可以阅读有关尿布反模式here
【解决方案4】:

IMO 最佳解决方案:有两个文件。

module_main.py

import actual_module.py

if __name__ != '__main__':
    raise RunTimeError("You should be importing actual_module.py, not module_main.py")

# Your "main" code

actual_module.py

# Actual module code (classes, functions, etc)

这是“干净”的,因为只有在实际出现问题时才会引发异常——任何人都不应该导入module_main.py,他们应该导入actual_module.py

愚人节解决方案

如果您使用的是 python 2.3,则有来自 entriangoto 模块,这显然有效!它是作为愚人节玩笑制作的,永远不应使用,(如果您查看源代码,您会明白原因:它增加了很多开销)但作为概念证明,它似乎就像我能找到的以任何简洁方式完成你想要的唯一方法。

from goto import goto, label

# Code that should always be imported (classes etc.)

if __name__ != "__main__":
    goto .end

# Stuff to be executed when this is main, NOT indented

label .end

【讨论】:

  • +1 以获得有趣的答案。 goto 模块对 sys.settrace() 的使用可能是真正答案的线索。
猜你喜欢
  • 2019-07-04
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
  • 2017-06-26
相关资源
最近更新 更多