目录:
- 涉及知识点
- Flask框架原理
- 简单示例
- 路由系统原理源码分析
- 请求流程简单源码分析
- 响应流程简单源码分析
- session简单源码分析
涉及知识点
1、装饰器
闭包思想
def wapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner """ 1. 立即执行wapper函数,并将下面装饰的函数当做参数传递 2. 将wapper函数返回值获取,在index赋值 index = inner函数 """ @wapper def index(): print('函数内容') # 实际执行的 inner函数,inner函数内部调用原函数 index()
[email protected],以上我们知道了python实现闭包,实际是index = inner(index)的封装思想。但不可避免的是inner封装后,会对封装的函数隐藏一些信息。如:包装异常,隐藏异常,打印日志,统计函数使用时间等。@functools.wraps通过update_wrapper函数,用参数wrapped表示的函数对象(例如:square)的一些属性(如:__name__、 __doc__)覆盖参数wrapper表示的函数对象(例如:callf,这里callf只是简单地调用square函数,因此可以说callf是 square的一个wrapper function)的这些相应属性。
import functools def wapper(func): @functools.wraps(func) def inner(*args,**kwargs): return func(*args,**kwargs) return inner @wapper def index(): print('函数内容') @wapper def order(): print('函数内容') print(index.__name__) print(order.__name__)
2、面向对象封装
class Foo(object): def __init__(self,age,name): self.age = age self.name = name class Bar(object): def __init__(self,counter): self.counter = counter self.obj = Foo('18','石鹏') b1 = Bar(1) print(b1.obj.name)
3、python对象什么后面可以加括号
- 函数
- 类
- 方法
- 对象
def f1(): print('f1') class F2(object): pass class F3(object): def __init__(self): pass def ff3(self): print('ff3') class F4(object): def __init__(self): pass def __call__(self, *args, **kwargs): print('f4') def func(arg): """ 由于arg在函数中加括号,所以他只有4中表现形式: - 函数 - 类 - 方法 - 对象 :param arg: :return: """ arg() # 1. 函数,内部执行函数 func(f1) # 2. 类,内部执行__init__方法 func(F2) # 3. 方法,obj.ff3 obj1 = F3() func(obj1.ff3) # 4. 对象 obj2 = F4() func(obj2)
4、call方法
class F4(object): def __init__(self): print('构造方法') def __call__(self, *args, **kwargs): print('f4') def run(self,str1): print("run:%s" % str1) obj = F4() obj() obj.run('sssss')
5、函数和方法的区别
在于调用时有没有实例化对象,即跟某个对象关联。
from types import MethodType,FunctionType class F3(object): def __init__(self): pass def ff3(self): print('ff3') # v1 = isinstance(F3.ff3,MethodType) # 方法 v2 = isinstance(F3.ff3,FunctionType) # 函数 print(v1,v2) # False,True obj = F3() v1 = isinstance(obj.ff3,MethodType) # 方法 v2 = isinstance(obj.ff3,FunctionType) # 函数 print(v1,v2) # True False
Flask框架原理
1、框架本质为通过socket模块实现工作流的请求和响应。
通过socket建立实例,accept等待请求地址,并通过编写路由系统来给予相应的响应。
import socket def main(): # 创建老师 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost', 8000)) sock.listen(5) while True: # 老师等待 用户请求的到来 connection, address = sock.accept() # 获取发送的内容:吴亦凡有没有女朋友? buf = connection.recv(1024) # 根据请求URL的不同: # 回答:没有 connection.send(b"HTTP/1.1 200 OK\r\n\r\n") connection.send(b"No No No") # 关闭连接 connection.close() if __name__ == '__main__': main()
2、flask通过werkzeug模块来帮助我们完成socket性能。
""" from werkzeug.wrappers import Request, Response from werkzeug.serving import run_simple @Request.application def hello(request): return Response('Hello World!') if __name__ == '__main__': # 当请求打来之后,自动执行:hello() run_simple('localhost', 4000, hello) """ from werkzeug.wrappers import Request, Response from werkzeug.serving import run_simple class Foo(object): def __call__(self, *args, **kwargs): return Response('Hello World!') if __name__ == '__main__': # 当请求打来之后,自动执行:hello() obj = Foo() run_simple('localhost', 4000, obj)
3、flask快速入门
""" pip install flask pip3 install flask """ from flask import Flask # 1. 实例化Flask对象 app = Flask('xxxx') """ 1. 执行 app.route('/index')并获取返回值 xx 2. @xx def index(): return 'Hello World' 3. 执行 index = xx(index) 本质: { '/index': index } """ @app.route('/index') def index(): return 'Hello World' if __name__ == '__main__': app.run()
简单示例
1、实现简单登陆
import functools from flask import Flask,render_template,request,redirect,session app = Flask('xxxx',template_folder="templates") app.secret_key = 'as923lrjks9d8fwlkxlduf' def auth(func): @functools.wraps(func) def inner(*args,**kwargs): user_info = session.get('user_info') if not user_info: return redirect('/login') return func(*args,**kwargs) return inner """ { /order: inner函数, name: order /index: inner函数, name: index } """ @app.route('/order',methods=['GET']) @auth def order(): user_info = session.get('user_info') if not user_info: return redirect('/login') return render_template('index.html') @app.route('/index',methods=['GET']) @auth def index(): return render_template('index.html') @app.route('/login',methods=['GET','POST']) def login(): if request.method == "GET": return render_template('login.html') else: user = request.form.get('user') pwd = request.form.get('pwd') if user == 'alex' and pwd == '123': session['user_info'] = user return redirect('/index') # return render_template('login.html',msg = "用户名或密码错误",x = 123) return render_template('login.html',**{'msg':'用户名或密码错误'}) @app.route('/logout',methods=['GET']) def logout(): del session['user_info'] return redirect('/login') if __name__ == '__main__': app.run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登录页面</h1> <form method="post"> <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit" value="提交">{{msg}} </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>欢迎进入系统</h1> <img src="/static/111.png" alt=""> </body> </html>
2、flask配置文件
import functools from flask import Flask # 配置:模板/静态文件 app = Flask('xxxx',template_folder="templates") # 配置:secret_key app.secret_key = 'as923lrjks9d8fwlkxlduf' # 导入配置文件 app.config.from_object('settings.TestingConfig') @app.route('/index') def index(): return "index" if __name__ == '__main__': app.run()
class BaseConfig(object): DEBUG = False SESSION_REFRESH_EACH_REQUEST = True class ProConfig(BaseConfig): pass class DevConfig(BaseConfig): DEBUG = True class TestingConfig(BaseConfig): DEBUG = True
ps.import importlib模块,模块支持传递字符串来导入模块。我们先来创建一些简单模块一遍演示。我们在模块里提供了相同接口,通过打印它们自身名字来区分。可通过importlib.import_module(module_path)来动态导入。其等价于import module_path。
路由系统原理源码分析
1、总体流程:
1.初始化Flask类,Rule类,Map类
2.调用app.route方法
3.route方法调用add_url_rule方法
4. add_url_rule方法rule = self.url_rule_class调用Rule方法,封装url和试图函数
5.add_url_rule方法调用url_map.add(Rule)对路由的rules进行添加[Rule('/index', 函数),]
6.map类存到self.url_map中,Rule存在url_rule_class中
import functools from flask import Flask,views # 配置:模板/静态文件 app = Flask('xxxx',template_folder="templates") """ { '/index': index函数 } 1. decorator = app.route('/index') 2. @decorator def index(): return "index" 3. decorator(index) """ """ Map() = [ Rule(rule=/index/ endpoint=None view_func=函数), ] """ @app.route('/index') def index(): return "index" """ Map() = [ Rule(rule=/index endpoint=None view_func=函数), Rule(rule=/order endpoint=None view_func=order), ] """ def order(): return 'Order' app.add_url_rule('/order', None, order) class TestView(views.View): methods = ['GET'] def dispatch_request(self): return 'test!' app.add_url_rule('/test', view_func=TestView.as_view(name='test')) # name=endpoint # app.add_url_rule('/test', view_func=view函数) # name=endpoint def auth(func): def inner(*args, **kwargs): print('before') result = func(*args, **kwargs) print('after') return result return inner class X1View(views.MethodView): methods = ['GET','POST'] decorators = [auth, ] def get(self): return 'x1.GET' def post(self): return 'x1.POST' app.add_url_rule('/x1', view_func=X1View.as_view(name='x1')) # name=endpoint if __name__ == '__main__': app.run()
2、初始化Flask类,Rule类,Map类
#-------------------------------------- # Flask类 class Flask(_PackageBoundObject): url_rule_class = Rule def __init__(self, import_name, static_path=None, static_url_path=None, static_folder='static', template_folder='templates', instance_path=None, instance_relative_config=False, root_path=None) self.url_map = Map() #-------------------------------------- # Role类 @implements_to_string class Rule(RuleFactory): def __init__(self, string, defaults=None, subdomain=None, methods=None, build_only=False, endpoint=None, strict_slashes=None, redirect_to=None, alias=False, host=None): if not string.startswith('/'): raise ValueError('urls must start with a leading slash') self.rule = string self.is_leaf = not string.endswith('/') self.map = None self.strict_slashes = strict_slashes self.subdomain = subdomain self.host = host self.defaults = defaults self.build_only = build_only self.alias = alias if methods is None: self.methods = None else: if isinstance(methods, str): raise TypeError('param `methods` should be `Iterable[str]`, not `str`') self.methods = set([x.upper() for x in methods]) if 'HEAD' not in self.methods and 'GET' in self.methods: self.methods.add('HEAD') self.endpoint = endpoint self.redirect_to = redirect_to if defaults: self.arguments = set(map(str, defaults)) else: self.arguments = set() self._trace = self._converters = self._regex = self._weights = None #------------------- #map类 class Map(object): default_converters = ImmutableDict(DEFAULT_CONVERTERS) def __init__(self, rules=None, default_subdomain='', charset='utf-8', strict_slashes=True, redirect_defaults=True, converters=None, sort_parameters=False, sort_key=None, encoding_errors='replace', host_matching=False): self._rules = [] self._rules_by_endpoint = {} self._remap = True self._remap_lock = Lock() self.default_subdomain = default_subdomain self.charset = charset self.encoding_errors = encoding_errors self.strict_slashes = strict_slashes self.redirect_defaults = redirect_defaults self.host_matching = host_matching self.converters = self.default_converters.copy() if converters: self.converters.update(converters) self.sort_parameters = sort_parameters self.sort_key = sort_key for rulefactory in rules or (): self.add(rulefactory)
3、调用app.route方法
def route(self, rule, **options): def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
4、route方法调用add_url_rule方法
@setupmethod def add_url_rule(self, rule, endpoint=None, view_func=None, **options): if endpoint is None: endpoint = _endpoint_from_view_func(view_func) options['endpoint'] = endpoint methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only ``GET`` as default. if methods is None: methods = getattr(view_func, 'methods', None) or ('GET',) if isinstance(methods, string_types): raise TypeError('Allowed methods have to be iterables of strings, ' 'for example: @app.route(..., methods=["POST"])') methods = set(item.upper() for item in methods) # Methods that should always be added required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. provide_automatic_options = getattr(view_func, 'provide_automatic_options', None) if provide_automatic_options is None: if 'OPTIONS' not in methods: provide_automatic_options = True required_methods.add('OPTIONS') else: provide_automatic_options = False # Add the required methods now. methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule)
5、 add_url_rule方法rule = self.url_rule_class调用Rule方法,封装url和试图函数
add_url_rule,代码同4 ;通过url_rule_class = Rule实例化,代码同2
6、add_url_rule方法调用url_map.add(Rule)对路由的rules进行添加[Rule('/index', 函数),]
add_url_rule代码同4,调用url_map.add方法
def add(self, rulefactory): """Add a new rule or factory to the map and bind it. Requires that the rule is not bound to another map. :param rulefactory: a :class:`Rule` or :class:`RuleFactory` """ for rule in rulefactory.get_rules(self): rule.bind(self) self._rules.append(rule) self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule) self._remap = True
7.map类存到self.url_map中,Rule存在url_rule_class中。
同代码2.