最近在对zabbix依赖的接口主动探测脚本做配置化改造,脚本里面用到了importlib提供的动态import功能,由于这一次一时性起全程vim操作没有用pycharm,vim一时爽,一直用一直爽,雾~ 等会我会说到不用pycharm导致的问题。

下面我用一个demo来复现一下问题,也便于大家理解,以下是目录结构和代码内容:

$ tree
├── demo
│   ├── cc_test.py
├── demo.py

$ cat demo.py
import importlib
path='cc'
lib=importlib.import_module('demo.'+path+'_test')
print(lib.ccc)

$ cat demo/cc_test.py
ccc='111'

你可以按照上面的目录结构和代码内容组织好,然后用python2运行一下,大致会报下面的错误,

$ python2 demo.py
Traceback (most recent call last):
  File "demo.py", line 3, in <module>
    lib=importlib.import_module('demo.'+path+'_test')
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/Users/sharp/Downloads/demo.py", line 3, in <module>
    lib=importlib.import_module('demo.'+path+'_test')
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
ImportError: No module named cc_test

总之会直接报没有叫cc_test的模块的错误,这样子就很迷惑了,你左看右看demo目录下都有一个叫cc_test.py的模块,怎么会没有呢,而当你不小心用python3来运行的时候会发现有的系统的源安装的python3可能什么错都不会报,正常输出结果,这就更让人迷惑了,当然还有一种输出,就是直接告诉你demo这个目录不是一个包,这时即使是python初学者也会知道给这个包加一个__init__.py的文件就可以解决问题了,如下:

$ python3 demo.py
Traceback (most recent call last):
  File "demo.py", line 3, in <module>
    lib=importlib.import_module('demo.'+path+'_test')
  File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/sharp/Downloads/demo.py", line 3, in <module>
    lib=importlib.import_module('demo.'+path+'_test')
  File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 962, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'demo.cc_test'; 'demo' is not a package

可是博主就非常不幸了,遇到了第一种情况,本地开发环境的python3什么错都不报,我也是折腾了个把小时才发现了问题,所以回到开始,我只想说pycharm大法好!因为pycharm新建包的时候会自动创建__init__.py。