首页 > 解决方案 > 如何从 __main__.py 访问 __init__.py 中的符号?

问题描述

我有一个模块——我们称之为模块——foo我想通过调用使其可用python -m foo。我的程序如下所示:

my_project
├──  foo
│   └── __init__.py
└── my_program.py

__init__.py我有一些我在调用时运行的代码python -m foo

def bar(name):
    print(name)

# -- code used to 'run' the module
def main(name):
    bar("fritz")

if __name__ == "__main__":
    main()

因为我现在有相当多的执行代码__init__.pyargparse东西和一些逻辑)我想把它分成一个__main__.py

my_project
├──  foo
│   ├── __init__.py
│   └── __main__.py
└── my_program.py

尽管这对我来说看起来很简单,但我还没有设法导入其中的东西__init__.py__main__.py

我知道 - 如果foo位于site-packages或通过PYTHONPATH我可以访问import foo..

但是,如果我想直接执行 (例如从某个 IDE)并位于任何位置(即不是 Python 查找包的文件夹) - 有没有办法导入(从同一目录)?__main__.py foofoo__init__.py

我试过import .import foo- 但两种方法都失败了(因为它们当然只是意味着别的)

能做的——至少解释我的目标——是这样的:

sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
import foo

有效,但丑陋且有点危险,因为我什至不知道我是否真的foo从同一目录导入..

标签: pythonpython-import

解决方案


您可以手动设置模块导入状态,就像使用以下__main__.py命令执行一样-m

# foo/__main__.py
import os
import sys
if __package__ is None and __name__ == "__main__":  # executed without -m
   # set special attributes as if part of the package
   __file__ = os.path.abspath(__file__)
   __package__ = os.path.basename(os.path.dirname(__file__))
   # replace import path for __main__ with path for package
   main_path = os.path.dirname(__file__)
   try:
       index = sys.path.index(dir_path)
       if index != 0 or index != 1:
           raise ValueError('expected script directory after current directory or matching it')
   except ValueError:
       raise RuntimeError('sys.path does not include script directory as expected')
   else:
       sys.path[index] = main_path
# import regularly
from . import bar

此漏洞作为独立脚本python3 path/to/foo/__main__.py执行: is并且也不包含包。在这种情况下,搜索路径是,但如果两者相同,它就会被折叠:是 0 或 1。__main____package__None__name__<current directory>, <__main__ directory>, ...index

与内部的所有诡计一样,存在一些违反不变量的瞬态。在模块修补之前不要执行任何导入!


推荐阅读