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

时间:2010-08-05 02:15:59

标签: python main init

我正在尝试从__main__.py内部访问模块的数据。

结构如下:

mymod/
    __init__.py
    __main__.py

现在,如果我在__init__.py中公开变量,就像这样:

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

如何从foo访问__main__.py

5 个答案:

答案 0 :(得分:23)

您需要将软件包放在sys.path中,将mymod的目录添加到sys.path中的__main__.py,或使用-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

有关详细讨论,请参阅this answer

答案 1 :(得分:4)

我遇到这种类型的问题最常见的问题是我经常要将__init__.py文件作为脚本运行来测试功能,但在加载包时不应运行这些。 python <package>/__init__.pypython -m <package>之间的不同执行路径有一个有用的解决方法。

  • $ python -m <module>执行<package>/__main__.py__init__.py未加载。
  • $ python <package>/__init__.py只是像普通脚本一样执行脚本__init__.py


问题

当我们希望__init__.pyif __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中的导入可能并不理想,因为我们正在将它们重新加载到另一个模块的本地范围内,尽管已在{{1}中加载它们已经,但显式加载应避免循环加载。如果您在__init__.py中再次加载整个__init__模块,则不会将其加载为main.py,因此就圆形加载而言应该是安全的。

答案 2 :(得分:2)

a package__init__模块就像包本身的成员一样,因此对象直接从mymod导入:

from mymod import foo

或者

from . import foo

如果您想要简洁,请阅读relative imports。您需要一如既往地确保不要将模块调用为mymod/__main__.py,因为这会阻止Python将mymod检测为包。您可以查看distutils

答案 3 :(得分:1)

如果您使用python -m mymod运行模块,则__main__.py中的代码将能够从模块的其余部分导入,而无需将模块添加到sys.path

答案 4 :(得分:0)

我发现第一个答案很有用(即,hacking sys.path),但是在 Python 3.4 中添加了 pathlib 后,我发现以下代码更加简单和 Pythonic:< /p>

import sys
from pathlib import Path

# You don't need to .insert(), just append
sys.path.append(str(Path(__file__).parent.parent))