PEP420使__init__.py
文件为可选:https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
尽管似乎没有它们,但pkgutil.walk_packages
不能按预期运行:https://docs.python.org/3/library/pkgutil.html#pkgutil.walk_packages
考虑以下示例:
$ tree foo
foo
├── bar
│ ├── baz.py
│ └── __init__.py
├── __init__.py
└── womp.py
和测试脚本
# test.py
import pkgutil
import foo
for _, mod, _ in pkgutil.walk_packages(foo.__path__, foo.__name__ + '.'):
print(mod)
在python2和python3中,我都得到以下输出:
$ python2.7 test.py
foo.bar
foo.bar.baz
foo.womp
$ python3.5 test.py
foo.bar
foo.bar.baz
foo.womp
删除
__init__.py
文件并且仅使用python3,我得到了以下信息:$ find -name '__init__.*' -delete
$ python3.5 test.py
foo.bar
这些模块绝对是可导入的:
$ python3.5 -c 'import foo.bar.baz'
$
这是一个错误吗?我是否被迫创建
__init__.py
文件来实现我想要的? 最佳答案
作为一种解决方法(可能会对其他人有所帮助),我正在使用类似的方法。它不是完美的(如果pwd更改或如果软件包不以。为根,则会中断),但是它确实可以满足我的简单用例:
def walk_modules(pkg):
assert hasattr(pkg, '__path__'), 'This function is for packages'
path = pkg.__name__.replace('.', '/')
modules = []
for root, _, filenames in os.walk(path):
for filename in filenames:
if filename.startswith('.') or not filename.endswith('.py'):
continue
path = os.path.join(root, filename)
modules.append(os.path.splitext(path)[0].replace('/', '.'))
for module in sorted(modules):
yield __import__(module, fromlist=['__trash'])