为什么当我导入模块时 Python 会运行它,我该如何停止它?
- 2024-11-29 08:41:00
- admin 原创
- 207
问题描述:
我正在构建一个 Python 程序,该程序可以以两种方式运行:第一种是调用python main.py
,它会以友好的方式提示用户输入,然后通过程序运行用户输入。另一种方法是调用,它会跳过所有友好的输入收集,并一次性通过程序运行整个文件的输入。python batch.py -file-
问题是,当我运行时batch.py
,它会从中导入一些变量/方法/等main.py
,并且当它运行以下代码时:
import main
在程序的第一行,它立即出错,因为它试图运行中的代码main.py
。
main
我怎样才能阻止 Python 运行我正在导入的模块中包含的代码?
解决方案 1:
因为这就是 Python 的工作方式 - 诸如class
和之类的关键字不是def
声明。相反,它们是被执行的真实语句。如果它们没有被执行,你的模块将是空的。
惯用的方法是:
# stuff to run always here such as class/def
def main():
pass
if __name__ == "__main__":
# stuff only to run when not called via 'import' here
main()
解决方案 2:
由于 Python 的工作方式,它必须在导入模块时运行它们。
为了防止模块中的代码在导入时被执行,但仅在直接运行时执行,您可以使用以下命令来保护它if
:
if __name__ == "__main__":
# this won't be run when imported
您可能希望将此代码放入main()
方法中,以便您可以直接执行文件,或导入模块并调用main()
。例如,假设这在文件中foo.py
。
def main():
print "Hello World"
if __name__ == "__main__":
main()
该程序可以通过python foo.py
,或者从另一个 Python 脚本运行:
import foo
...
foo.main()
解决方案 3:
使用if __name__ == '__main__'
习惯用法 --是一个特殊变量,如果模块作为脚本运行,则__name__
其值为;如果模块被导入,则其值为模块名称。因此,您可以执行类似以下操作'__main__'
# imports
# class/function definitions
if __name__ == '__main__':
# code here will only run when you invoke 'python main.py'
解决方案 4:
不幸的是,你不需要。这是 import 语法的一部分,并且这样做很重要 —— 记住def
这实际上是执行了某些操作,如果 Python 没有执行 import,那么你将无法使用任何函数。
不过,由于您可能有权访问该文件,因此您可能能够查看并找出导致错误的原因。也许可以修改您的环境以防止发生错误。
解决方案 5:
曾经有一个 Python 增强提案PEP 299,旨在if __name__ == '__main__':
用 替换 idiom def __main__:
,但被否决了。阅读这篇文章,了解使用 时应注意什么,仍然值得一读if __name__ = '__main__':
。
解决方案 6:
将代码放入函数中,只有调用该函数时,它才会运行。你的main.py
. 中应该有一个 main 函数,其语句如下:
if __name__ == '__main__':
main()
然后,如果您调用python main.py
该main()
函数,它将运行。如果您导入main.py
,则不会运行。此外,main.py
为了清晰起见,您可能应该将其重命名为其他名称。
解决方案 7:
我做了一个简单的测试:
测试.py
x = 1
print("1, has it been executed?")
def t1():
print("hello")
print("2, has it been executed?")
def t2():
print("world")
print("3, has it been executed?")
def main():
print("Hello World")
print("4, has it been executed?")
print("5, has it been executed?")
print(x)
# while True:
# t2()
if x == 1:
print("6, has it been executed?")
测试2.py
import test
当执行或者运行test2.py时,运行结果:
1, has it been executed?
5, has it been executed?
1
6, has it been executed?
结论:当导入的模块没有添加 时if __name__=="__main__":
,运行当前模块, 导入的模块中不是函数内的代码会顺序执行,函数内的代码没有被调用时不会执行。
此外:
def main():
# Put all your code you need to execute directly when this script run directly.
pass
if __name__ == '__main__':
main()
else:
# Put functions you need to be executed only whenever imported
解决方案 8:
你可以像这样编写你的“main.py”:
#!/usr/bin/env python
__all__=["somevar", "do_something"]
somevar=""
def do_something():
pass #blahblah
if __name__=="__main__":
do_something()
解决方案 9:
可能发生的一个小错误(至少发生在我身上),特别是在分发执行完整分析的 Python 脚本/函数时,就是直接在函数 .py 文件的末尾调用该函数。用户唯一需要修改的是输入文件和参数。在导入时这样做,您将立即运行该函数。为了获得正确的行为,您只需删除对函数的内部调用并将其保留给实际调用文件/函数/代码部分
解决方案 10:
另一个选项是使用二进制环境变量,例如我们将其称为“run_code”。如果 run_code = 0(False),则构造 main.py 以绕过代码(但暂时绕过的函数仍将作为模块导入)。稍后,当您准备使用导入的函数(现在是模块)时,请设置环境变量 run_code = 1(True)。使用 os.environ 命令设置和检索二进制变量,但请确保在检索时将其转换为整数(或重构 if 语句以读取字符串值),
在main.py中:
import os
#set environment variable to 0 (False):
os.environ['run_code'] = '0'
def binary_module():
#retrieve environment variable, convert to integer
run_code_val = int(os.environ['run_code'] )
if run_code_val == 0:
print('nope. not doing it.')
if run_code_val == 1:
print('executing code...')
# [do something]
...在加载 main.py 的任何脚本中:
import os,main
main.binary_module()
输出:不,没有这样做。
# now flip the on switch!
os.environ['run_code'] = '1'
main.binary_module()
输出:执行代码...
*注意:以上代码假定 main.py 和它导入的任何脚本都存在于同一目录中。
解决方案 11:
尽管您无法import
在不运行代码的情况下使用,但有一种相当快捷的方法可以输入变量;通过使用numpy.savez
,它将变量作为 numpy 数组存储在 .npz 文件中。之后,您可以使用加载变量numpy.load
。
请参阅scipy 文档中的完整描述
请注意,这仅适用于变量和变量数组,不适用于方法等。
解决方案 12:
尝试从 main.py 导入所需的函数?那么,
from main import SomeFunction
可能是您将 batch.py 中的函数命名为与 main.py 中的函数相同,并且当您导入 main.py 时,程序将运行 main.py 函数而不是 batch.py 函数;执行上述操作应该可以解决该问题。我希望如此。