在__main__.py中使用模块的对象
我想在一个模块的 __main__.py
文件里访问它的数据。
这个模块的结构是这样的:
mymod/
__init__.py
__main__.py
现在,如果我在 __init__.py
文件里这样暴露一个变量:
__all__ = ['foo']
foo = {'bar': 'baz'}
我该怎么在 __main__.py
文件里访问 foo
呢?
6 个回答
我遇到的一个常见问题是,我经常想把 __init__.py
文件当作脚本来运行,以测试一些功能,但这些功能在加载包的时候不应该被执行。这里有一个很有用的解决办法,可以处理 python <package>/__init__.py
和 python -m <package>
之间不同的执行路径。
$ python -m <module>
会执行<package>/__main__.py
,而不会加载__init__.py
。$ python <package>/__init__.py
则会像普通脚本一样直接执行__init__.py
。
问题
当我们希望 __init__.py
中有一个 if __name__ == '__main__': ...
的条件语句,并且这个语句需要使用 __main__.py
中的内容时,我们就会遇到麻烦。我们不能导入 __main__.py
,因为它总是会从解释器的路径中导入 __main__.pyc
文件。除非…我们使用绝对路径导入的技巧,这样可能会引发很多其他问题。
解决方案 一种解决方案 :)
为模块的 __main__
使用两个脚本文件:
<package>/
__init__.py
__main__.py
main.py
# __init__.py
# ...
# some code, including module methods and __all__ definitions
__all__ = ['foo', 'bar']
bar = {'key': 'value'}
def foo():
return bar
# ...
if __name__ == '__main__':
from main import main
main.main()
# __main__.py
# some code...such as:
import sys
if (len(sys.argv) > 1 and sys.argv[1].lower() == 'option1'):
from main import main()
main('option1')
elif (len(sys.argv) > 1 and sys.argv[1].lower() == 'option2'):
from main import main()
main('option2')
else:
# do something else?
print 'invalid option. please use "python -m <package> option1|option2"'
# main.py
def main(opt = None):
if opt == 'option1':
from __init__ import foo
print foo()
elif opt == 'option2':
from __init__ import bar
print bar.keys()
elif opt is None:
print 'called from __init__'
在 main.py
中的导入可能不是最理想的,因为如果我们从 __init__.py
运行时,会把它们重新加载到另一个模块的本地作用域中,尽管我们已经在 __init__.py
中加载过了,但这样明确的加载应该可以避免循环加载。如果你在 main.py
中再次加载整个 __init__
模块,它不会被当作 __main__
加载,所以在循环加载方面应该是安全的。
你需要确保这个包已经在 sys.path
里面,或者在 __main__.py
文件中把包含 mymod
的目录添加到 sys.path
,或者使用 -m
这个选项。
如果要把 mymod
添加到路径,代码大概是这样的(在 __main__.py
中):
import sys
import os
path = os.path.dirname(sys.modules[__name__].__file__)
path = os.path.join(path, '..')
sys.path.insert(0, path)
from myprog import function_you_referenced_from_init_file
使用 -m
选项的方式是这样的:
python -m mymod
想了解更多,可以查看 这个回答。