Flask插件原理
Flask的插件还挺多,用过的都知道比如flask-sqlalchemy,安装的时候是使用pip install flask-sqlalchemy,使用的时候就成了from flask.ext.sqlalchemy import SQLAlchemy。使用的是flask.ext而不是flask_sqlalchemy。感觉还有点牛掰啊-_-,不过仅仅是看起来高大上,并没有什么卵用。在2016年4月13号正式被移出支持了,已经直接发出不建议使用的警告。本文还是来炒一下现饭,看看它背后的逻辑
比如flask-sqlalchemy原本是使用from flask_sqlalchemy import [anything]使用的,被变成了from flask.ext.sqlalchemy import [anything]。这是一种对于import的hook。我们知道要导入一个模块,不使用import声明也是可以的,可以使用__import__函数,返回得到的也是一个模块对象
import hook
下文简述,如果需要了解比较详细的资料可以查看后文给出的参考链接(python2和3的import机制是略有区别的)
import声明主要做了2件事情,查找模块,加载模块。我们说的hook发生在第一步查找模块。查找模块的步骤是
- 查找sys.modules缓存
- 在sys.meta_path中依次执行finder对象,找到就返回自身,所有的都没有找到则会报错
注意:sys.path_hooks中的finder会被sys.meta_path调用执行(sys.meta_path和sys.path_hook都可以参与import hooks步骤)
精简版本实现
1 | import sys |
ExtensionImporter是一个finder对象,当执行import flask.ext时会把它加入到sys.meta_path列表,后续的import都会先执行它,判断满足要求后就会使用__import__导入然后加入到sys.modules,这样就实现了flask.ext.sqlalchemy导入
为什么会被废除呢。下面是我猜测的。首先本来这个东西没有实质的作用,就是看着炫酷而已。我们可以认为所有的扩展导入都会使用flask.ext.xxx,但是这对第三方扩展库是有要求的,那就是包名必须为flask_xxx才行,我猜测有的第三方库未必遵守这个规则(否则exthook.py中也不会出现['flask_%s', 'flaskext.%s'flaskext.另外一种形式),这就说明了有的作者使用了flaskextxxx这种包名。出现了第二种难免就会出现另外的。当使用者发现并非所有的第三方扩展都使用flask.ext导入的时候。社区也觉得没必要维持了,毕竟第一个写这个代码的人是不是因为刚刚了解了import机制,觉得很炫酷写上去的呢-_-,另外这种花哨的设计也可能对代码自动补全功能产生了负面影响。so,最后还是回到了原来的位置,直接使用import flask_sqlalchemy导入吧