在__main__.py中使用模块的对象

47 投票
6 回答
15361 浏览
提问于 2025-04-16 02:20

我想在一个模块的 __main__.py 文件里访问它的数据。

这个模块的结构是这样的:

mymod/
    __init__.py
    __main__.py

现在,如果我在 __init__.py 文件里这样暴露一个变量:

__all__ = ['foo']
foo = {'bar': 'baz'}

我该怎么在 __main__.py 文件里访问 foo 呢?

6 个回答

3

一个包的 __init__ 模块就像这个包的成员一样,所以你可以直接从 mymod 中导入对象:

from mymod import foo

或者

from . import foo

如果你想简洁一点,可以了解一下 相对导入。你需要确保,不要像 mymod/__main__.py 这样调用模块,因为这样会让 Python 无法把 mymod 识别为一个包。你可能还想看看 distutils

4

我遇到的一个常见问题是,我经常想把 __init__.py 文件当作脚本来运行,以测试一些功能,但这些功能在加载包的时候不应该被执行。这里有一个很有用的解决办法,可以处理 python <package>/__init__.pypython -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__ 加载,所以在循环加载方面应该是安全的。

23

你需要确保这个包已经在 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

想了解更多,可以查看 这个回答

撰写回答