Flask框架整个流程源码解读
Posted Hank·Paul
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask框架整个流程源码解读相关的知识,希望对你有一定的参考价值。
Flask框架整个流程源码解读
""" app.run() 本质执行的是 run_simple(ip,host,self) self 是当前的app对象 app.__call__ """
_request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app) request = LocalProxy(partial(_lookup_req_object, "request")) session = LocalProxy(partial(_lookup_req_object, "session"))
def wsgi_app(self, environ, start_response): # RequestContext的对象,其中包含当前请求的东西。 ctx = self.request_context(environ) error = None try: try: #RequestContext的对象,ctx.push,就执行是RequestContext对象的push方法 #ctx放入local中 ctx.push() #请求扩展以及响应函数 response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: # noqa: B001 error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
# 1 我们self.request_context(environ)执行是:所以ctx是RequestContext(self, environ)的返回值: def request_context(self, environ): #等一下返回的ctx就是RequestContext()执行的结果。 return RequestContext(self, environ) #2 RequestContext(self, environ)的执行结果是什么?是RequestContext的对象,这个对象中包含了reuqest等信息 class RequestContext(object): #app, environ,ctx,就是RequestContext的对象, def __init__(self, app, environ, request=None, session=None): self.app = app if request is None: request = app.request_class(environ) self.request = request
#1 ctx.push方法就执行RequestContext的对象的push方法: #源码: def push(self): #当前的self是RequestContext的对象,也就是ctx, _request_ctx_stack.push(self) #2 _request_ctx_stack,我们发现它是全局LocalStack()的对象。 #_request_ctx_stack.push(self)就是执行LocalStack中的push方法,并且把ctx传给了#_request_ctx_stack.push的push方法。self=ctx #LocalStack中的push源码: def push(self, obj): rv = getattr(self._local, "stack", None) if rv is None: #storage[线程,协程id]["stack"] = [] self._local.stack = rv = [] rv.append(obj) return rv #上述代码中的self._local是Local对象,用来保证数据安全。 #当代码执行self._local.stack = rv = [],再Local对象中的存储结构是:storage[线程,协程id]["stack"] = [] # rv.append(obj),把storage[线程,协程id]["stack"] = [obj],又由于obj=ctx,就算就是把ctx放入到Local对象中。结构如下Local().storage[线程,协程id]["stack"] = [ctx]
#1 #这句话我们执行是请扩展与响应函数 #再响应函数和请求扩展中就可以使用request,它是如果和实现的呢? from flask import Flask,request,session app = Flask(__name__) def index(): print(request.method) print(session) return "ok" #比如上面代码中request.method,是如何拿到请求相关的内容呢? #2 #我们点进去看request是什么? request = LocalProxy(partial(_lookup_req_object, "request")) #我们发现request就是 LocalProxy的对象。 #那我们再LocalProxy应该能找到method属性,但是发现没有,既然没有,它就一定写了__getattr__ #我们看__getattr__的源码: def __getattr__(self, name): #request.method,现在的name就是method if name == "__members__": return dir(self._get_current_object()) #现在的name是method,self._get_current_object()执行结果就偏函数的执行结果 #偏函数的执行结果中来获取method #偏函数的执行结果就是request. #etattr(request, method) return getattr(self._get_current_object(), name) #3 #我们再看看_get_current_object()它的执行结果是什么? #self._get_current_object()的源码: def _get_current_object(self): return self.__local() #上面的self._get_current_object()执行结果就是self.__local()的执行结果 # 4 #self.__local是什么? #我们发现这个self.__local是实例化的时候传递的,也就local,代码如下 def __init__(self, local, name=None): #self.__local= _LocalProxy__local=local = partial(_lookup_req_object, "request") #self.__local设置为隐藏属性, object.__setattr__(self, "_LocalProxy__local", local) # self.__local=local #local是实例化的时候传递的。我们实例化这个 LocalProxy(partial(_lookup_req_object, "request")) # 我们self._get_current_object=self.__local=local=partial(_lookup_req_object, "request") #5 #那最终我们明白了: def __getattr__(self, name): #request.method,现在的name就是method if name == "__members__": return dir(self._get_current_object()) return getattr(self._get_current_object(), name) #self._get_current_object() 执行结果,就partial(_lookup_req_object, "request")的执行结果。 #就是ctx.request,所以getattr(self._get_current_object(), name)相当于getattr(ctx.request, method) #6 #partial(_lookup_req_object, "request")()执行的结果 #_lookup_req_object的代码如下: def _lookup_req_object(name): #这里的name,是"request" top = _request_ctx_stack.top #top是谁?是ctx. if top is None: raise RuntimeError(_request_ctx_err_msg) #top里面找request,也就是top= ctx--》ctx里面找request. return getattr(top, name) # 7 #又因为_request_ctx_stack是LocalStack()的对象,所以 _request_ctx_stack.top就是执行LocalStack()的对象中的top: #_request_ctx_stack.top的源码: @property def top(self): try: # storage[线程,协程id]["stack"] = [ctx] #现在top的retrun值就ctx return self._local.stack[-1] except (AttributeError, IndexError): return None #代码中的self._local是Local对象,是我们存ctx的时候的Local对象。
以上是关于Flask框架整个流程源码解读的主要内容,如果未能解决你的问题,请参考以下文章