Yifei Kong

Aug 05, 2017

Python 的 import 系统与 importlib

首先

init.py is first called before the actual import

if you have the following code:

foobar/
    __init__.py
    baz.py

runing import foobar will not make foobar.baz available you have to add from . import baz to init.py

add all to init..py to control which to be imported by import *

relative import

from . import grok
from ..B import bar
relavtive import only works when using -m option
python -m mypackage.A.spam

by calling import foo, foo/init.py will be called

常见的问题

implicit import

需要注意的是 python2 中支持隐式的从当前文件import当前目录的文件。 这个功能在python3 中已经被去掉了。

Q&A

如何处理循环引用的问题?

把一些import语句放到真正需要他们的地方, 比如某个函数里面

importlib

之所以想研究importlib,是因为leader提到了Thrift应该把源文件提交到仓库中,而不是把编译后的文件提交到仓库中,而python运行是没有预编译机制的,那么就需要一套机制来在runtime动态的编译加载thrift文件。第一个想法当然是写一个import_thrift函数,大概是这样的:

def import_thrfit(package, *names):
    _compile_thrift(package)  # compile *.thrift files
    if not objects:
        import module_name
    else:
        from module_name import *names

但是,显然直接使用import语句是不可以的,因为import是一个语句,后边跟的不能是变量。这时候就需要import背后的库importlib的帮助了。再者,当多次调用这个函数的时候,我们希望有缓存,而不是每次编译一次

介绍importlib

importlib实现了两个功能,1. 提供了import的实现,2. 提供了import_module函数,这样我们就可以实现自己的import系统。本文中我们主要关注第二点。

importlib.import_module

importlib.import_module(name, package=None) 如果name是相对包名,name将从package中相对导入这个包,比如..mod,package是package.subpkg,将会导入package.mod这个包。如果name是绝对包名,那就直接导入。需要注意的是在上述例子中,返回的是package.mod这个名字而不是单独的mod名称。

有了这个函数我们就可以实现 import_thrift 了