一、中间件
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello World!' # 模拟中间件 class Md(object): def __init__(self, old_wsgi_app): self.old_wsgi_app = old_wsgi_app def __call__(self, environ, start_response): print('开始之前') ret = self.old_wsgi_app(environ, start_response) print('结束之后') return ret if __name__ == '__main__': # 1我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法 # 2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。 # 3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。 # 4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。 # 把原来的wsgi_app替换为自定义的, aaa=Md(app.wsgi_app) app.wsgi_app = aaa app.run() # flask请求来了会执行,执行app()--->触发:类的__call__ # app.__call__---->self.wsgi_app(environ, start_response) # 请求来了以后,会执行Md对象的__call__ # aaa(environ, start_response)--->Md类的__call__()
二、蓝图
1 是一个类的对象,用来划分项目目录,为了避免使用app划分目录的时候出现循环导入问题 2 使用步骤 -实例化得到一个蓝图对象 from flask import Blueprint account = Blueprint('account', __name__) -像使用app一样使用蓝图,注册路由 @account.route('/login.html', methods=['GET', "POST"]) def login(): return render_template('login.html') -在app中注册蓝图 from .views.account import account app.register_blueprint(account) 3 注意点: 1 蓝图注册进app时,指定前缀(类似于路由分发) app.register_blueprint(admin, url_prefix='/admin') 2 蓝图对象在实例化的时候,可以指定当前蓝图使用哪个模板文件夹和静态文件夹 如果不指定,默认用app的,查找顺序是先从自己里面找,找不到再找app的 web = Blueprint('web',__name__,template_folder='templates',static_folder='static') 3 蓝图对象有自己的请求扩展,请求扩展只属于当前蓝图 # 只有访问当前蓝图管理的路径才会触发请求扩展 web = Blueprint('web', __name__,template_folder='templates',static_folder='static') @web.before_request def web_request(): print('web request') @web.after_request def web_after(response): print(response) return response
三、flask请求上下文
1 当flask启动,等待客户端请求 2 一旦请求来了:app()--->app.__call__()---->app.wsgi_app() 3 wsgi_app()源码如下: # environ:http请求字典 # 返回一个ctx=RequestContext,对象中有Request对象,Session对象。。。 ctx = self.request_context(environ) error = None try: try: # 把ctx对象放到了全局变量_request_ctx_stack中 # _request_ctx_stack全局变量是LocalStack的对象 # LocalStack类的push方法 ''' def push(self, obj): rv = getattr(self._local, "stack", None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rvbefore_first_request,before_request,after_request ''' ctx.push() # 执行请求扩展的东西(before_first_request,before_request,after_request) # 根据路径执行视图函数 response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
四、requitrments.txt
1 在虚拟环境中直接导出 pip3 freeze >requirements.txt 2 系统环境装了很多模块,只导出当前项目依赖的模块 -pip3 install pipreqs -pipreqs ./ --encoding=utf8
五、threading.local
# 不用local,会出现并发安全的问题 # from threading import Thread # import time # lqz = -1 # def task(arg): # global lqz # lqz = arg # # time.sleep(2) # print(lqz) # # for i in range(10): # t = Thread(target=task,args=(i,)) # t.start() # 使用local # from threading import Thread from threading import local # import time # from threading import get_ident # # 特殊的对象,不同线程操作它,操作的是线程自己的,不会出现并发安全问题 # lqz = local() # def task(arg): # # 对象.val = 1/2/3/4/5 # lqz.value = arg # time.sleep(2) # print(lqz.value) # for i in range(10): # t = Thread(target=task,args=(i,)) # t.start() # 自己写个local对象(low版本) # from threading import get_ident,Thread # import time # storage = {} # # {线程id号1:{key:value},线程id号2:{key:value},线程id号3:{key:value}} # def set(k,v): # ident = get_ident() # 获取线程id号 # if ident in storage: # storage[ident][k] = v # else: # storage[ident] = {k:v} # def get(k): # ident = get_ident() # return storage[ident][k] # def task(arg): # set('val',arg) # time.sleep(2) # v = get('val') # print(v) # # for i in range(10): # t = Thread(target=task,args=(i,)) # t.start() # 面向对象版本 # from threading import get_ident,Thread # import time # class Local(object): # storage = {} # # {线程id号1: {key: value}, 线程id号2: {key: value}, 线程id号3: {key: value}} # def set(self, k, v): # ident = get_ident() # if ident in Local.storage: # Local.storage[ident][k] = v # else: # Local.storage[ident] = {k: v} # def get(self, k): # ident = get_ident() # return Local.storage[ident][k] # obj = Local() # def task(arg): # obj.set('val',arg) # v = obj.get('val') # print(v) # for i in range(10): # t = Thread(target=task,args=(i,)) # t.start() # 面向对象版本,通过.取值,赋值 # from threading import get_ident,Thread # import time # class Local(object): # storage = {} # ## {线程id号1: {key: value}, 线程id号2: {key: value}, 线程id号3: {key: value}} # def __setattr__(self, k, v): # ident = get_ident() # if ident in Local.storage: # Local.storage[ident][k] = v # else: # Local.storage[ident] = {k: v} # def __getattr__(self, k): # ident = get_ident() # return Local.storage[ident][k] # obj = Local() # obj2 = Local() # 所有的local对象用的是同一个字典,不好 # def task(arg): # obj.val = arg # print(obj.val) # for i in range(10): # t = Thread(target=task,args=(i,)) # t.start() # 不同local对象,使用自己的字典 # from threading import get_ident,Thread # import time # class Local(object): # def __init__(self): # # self.storage={} 递归 # # setattr(self,'storage',{}) 递归 # #Local.__setattr__(self,'storage',{}) # # object.__setattr__(self,'storage',{}) # # def __setattr__(self, k, v): # ident = get_ident() # if ident in self.storage: # self.storage[ident][k] = v # else: # self.storage[ident] = {k: v} # def __getattr__(self, k): # ident = get_ident() # return self.storage[ident][k] # obj = Local() # def task(arg): # obj.val = arg # # obj.xxx = arg # time.sleep(1) # print(obj.val) # for i in range(10): # t = Thread(target=task,args=(i,)) # t.start() # 多线程下可以使用,一旦加入协程,就不行了 # 自定义一个兼容线程和协程的local对象 try: from greenlet import getcurrent as get_ident except Exception as e: from threading import get_ident from threading import Thread import time class Local(object): def __init__(self): object.__setattr__(self,'storage',{}) def __setattr__(self, k, v): ident = get_ident() if ident in self.storage: self.storage[ident][k] = v else: self.storage[ident] = {k: v} # try: # storage[ident][name] = value # except KeyError: # storage[ident] = {name: value} def __getattr__(self, k): ident = get_ident() return self.storage[ident][k] obj = Local() def task(arg): obj.val = arg # obj.xxx = arg print(obj.storage) print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
四、偏函数
from functools import partial # 偏函数 def add(a,b,c): return a+b+c add=partial(add,2) # add是一个偏函数了,提前传值 print(add) # print(add(3,4)) print(add(2,3,4)) # print(add(2,3,4))