Flask第三方插件扩展原理
flask这种轻量级的框架本身并没有包含我们需要的功能,因此必须通过扩展插件才可以。今天学习了FLask的扩展插件导入(import)原理。
通常我们import第三方插件时,如:flask.ext.principal import identity_loaded。
当执行该语句时,首先要执行flask/ext/
init
.py模块,该模块内函数如下:
def setup(): from ..exthook import ExtensionImporter importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], name ) importer.install()
setup() del setup
看如上代码,会创建一个importer类,执行install方法,再往下看,调到ExtensionImporter类。
def install(self): sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self]
sys.meta_path要优先于sys.path。
也就是说当执行flask.ext.principal import identity_loaded时,会调用find_modules(flask.ext.principal),根据重载的函数,我们可以找到真实的模块名称(一般为flask_principal,flaskext_principal),即作用相当于import flask_principal。下面是find_module和load_module的method.
code> def find_module(self, fullname, path=None): if fullname.startswith(self.prefix): return selfdef load_module(self, fullname): if fullname in sys.modules: return sys.modules[fullname] modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff] for path in self.module_choices: realname = path % modname try: __import__(realname) except ImportError: exc_type, exc_value, tb = sys.exc_info() # since we only establish the entry in sys.modules at the # very this seems to be redundant, but if recursive imports # happen we will call into the move import a second time. # On the second invocation we still don't have an entry for # fullname in sys.modules, but we will end up with the same # fake module name and that import will succeed since this # one already has a temporary entry in the modules dict. # Since this one "succeeded" temporarily that second # invocation now will have created a fullname entry in # sys.modules which we have to kill. sys.modules.pop(fullname, None) # If it's an important traceback we reraise it, otherwise # we swallow it and try the next choice. The skipped frame # is the one from __import__ above which we don't care about if self.is_important_traceback(realname, tb): reraise(exc_type, exc_value, tb.tb_next) continue module = sys.modules[fullname] = sys.modules[realname] if '.' not in modname: setattr(sys.modules[self.wrapper_module], modname, module) return module raise ImportError('No module named %s' % fullname)
微信分享/微信扫码阅读