Flask进阶
Posted zhangyafei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask进阶相关的知识,希望对你有一定的参考价值。
知识补充
threading.local
作用:为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)。
""" import threading from threading import local import time obj = local() def task(i): obj.xxxxx = i time.sleep(2) print(obj.xxxxx,i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() """ """ import threading from threading import local def task(i): print(threading.get_ident(),i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() """ """ import time import threading import greenlet DIC = {} def task(i): # ident = threading.get_ident() ident = greenlet.getcurrent() if ident in DIC: DIC[ident][‘xxxxx‘] = i else: DIC[ident] = {‘xxxxx‘:i } time.sleep(2) print(DIC[ident][‘xxxxx‘],i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() """ import time import threading try: import greenlet get_ident = greenlet.getcurrent except Exception: get_ident = threading.get_ident class Local(object): DIC = {} def __getattr__(self, item): ident = get_ident() if ident in self.DIC: return self.DIC[ident].get(item) return None def __setattr__(self, key, value): ident = get_ident() if ident in self.DIC: self.DIC[ident][key] = value else: self.DIC[ident] = {key: value} obj = Local() def task(i): obj.xxxxx = i time.sleep(2) print(obj.xxxxx, i) for i in range(10): t = threading.Thread(target=task, args=(i, )) t.start()
- 如何获取一个线程的唯一标记? threading.get_ident() - 根据字典自定义一个类似于threading.local功能? import time import threading DIC = {} def task(i): ident = threading.get_ident() if ident in DIC: DIC[ident][‘xxxxx‘] = i else: DIC[ident] = {‘xxxxx‘:i } time.sleep(2) print(DIC[ident][‘xxxxx‘],i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() - 根据字典自定义一个为每个协程开辟空间进行存取数据。 import time import threading import greenlet DIC = {} def task(i): # ident = threading.get_ident() ident = greenlet.getcurrent() if ident in DIC: DIC[ident][‘xxxxx‘] = i else: DIC[ident] = {‘xxxxx‘:i } time.sleep(2) print(DIC[ident][‘xxxxx‘],i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() - 通过getattr/setattr 构造出来 threading.local的加强版(协程) import time import threading try: import greenlet get_ident = greenlet.getcurrent except Exception as e: get_ident = threading.get_ident class Local(object): DIC = {} def __getattr__(self, item): ident = get_ident() if ident in self.DIC: return self.DIC[ident].get(item) return None def __setattr__(self, key, value): ident = get_ident() if ident in self.DIC: self.DIC[ident][key] = value else: self.DIC[ident] = {key:value} obj = Local() def task(i): obj.xxxxx = i time.sleep(2) print(obj.xxxxx,i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start()
应用:DBUtils中为每个线程创建一个数据库连接时使用
一、上下文管理
两类请求:请求上下文,app上下文
上下文管理的实现(重点)
当请求到来的时候, flask会把请求相关和session相关信息封装到一个ctx = RequestContext对象中, 会把app和g封装到app_ctx = APPContext对象中去, 通过localstack对象将ctx、app_ctx对象封装到local对象中 问题: local是什么?作用? 为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离) localstack是什么?作用 storage = { 1234:{stack:[ctx,]} } localstack将local中的stack中的维护成一个栈 获取数据(执行视图函数的时候) 通过导入一个模块,用模块.的方式获取我们想要的数据 实现细节: 通过localproxy对象+偏函数,调用localstack去local中获取对应的响应ctx、app_ctx中封装值 问题:为什么要把ctx = request/session app_ctx = app/g 因为离线脚本需要使用app_ctx 请求结束 调用localstk的pop方法,将ctx和app_ctx移除
1. 请求上下文管理
知识补充:
- 偏函数:给函数取一个默认的参数,这样可以使函数不必每一次都传参。 应用:request = LocalProxy(partial(_lookup_req_object, ‘request‘)) session = LocalProxy(partial(_lookup_req_object, ‘session‘)) import functools def index(a1,a2): return a1 + a2 # 原来的调用方式 # ret = index(1,23) # print(ret) # 偏函数,帮助开发者自动传递参数 new_func = functools.partial(index,666) ret = new_func(1) print(ret)
- super和执行类的区别? """ class Base(object): def func(self): print(‘Base.func‘) class Foo(Base): def func(self): # 方式一:根据mro的顺序执行方法 # super(Foo,self).func() # 方式二:主动执行Base类的方法 # Base.func(self) print(‘Foo.func‘) obj = Foo() obj.func() """ #################################### class Base(object): def func(self): super(Base, self).func() print(‘Base.func‘) class Bar(object): def func(self): print(‘Bar.func‘) class Foo(Base,Bar): pass # 示例一 # obj = Foo() # obj.func() # print(Foo.__mro__) # 示例二 # obj = Base() # obj.func()
# -*- coding: utf-8 -*- ‘‘‘ # @Datetime: 2018/12/23 # @author: Zhang Yafei ‘‘‘ ‘‘‘ class Base(object): def func(self): print(‘Base_func‘) class Foo(Base): def func(self): # 方式一:根据mro的顺序执行方法 # super(Foo, self).func() # 方式二:主动执行Base类的方法 # Base.func(self) print(‘Foo_func‘) obj = Foo() obj.func() ‘‘‘ ############################### super和执行父类的方法的区别 ################### class Base(object): def func(self): super(Base, self).func() print(‘Base_func‘) class Bar(object): def func(self): print(‘Bar_func‘) class Foo(Base, Bar): pass obj = Foo() obj.func() print(Foo.__mro__) # obj = Base() print(Base.__mro__) # obj.func()
# -*- coding: utf-8 -*- ‘‘‘ # @Datetime: 2018/12/23 # @author: Zhang Yafei ‘‘‘ class Foo(object): def __init__(self): object.__setattr__(self, ‘storage‘, {}) def __setattr__(self, key, value): print(key, value, self.storage) obj = Foo() obj.xx = 123
class Stack(object): """栈""" def __init__(self): self.__list = [] #私有变量,不允许外部调用者对其进行操作 def push(self,item): """添加一个新的元素item到栈顶""" self.__list.append(item) #顺序表尾部插入时间复杂度O(1),头部插入O(n),故尾部方便 #self.__list.insert(0,item) #链表表尾部插入时间复杂度O(n),头部插入O(1),故链表用头插方便 def pop(self): """弹出栈顶元素""" return self.__list.pop() if __name__ == ‘__main__‘: s = Stack() s.push(1) s.push(2) s.push(3) s.push(4) print(s.pop()) print(s.pop()) print(s.pop()) print(s.pop())
‘‘‘ # @Datetime: 2018/12/25 # @author: Zhang Yafei ‘‘‘ class Obj(object): def func(self): pass # 执行方法一 # obj = Obj() # obj.func() # 方法 # 执行方法二 # obj = Obj() # Obj.func(obj) # 函数 from types import FunctionType, MethodType obj = Obj() print(isinstance(obj.func, FunctionType)) # False print(isinstance(obj.func, MethodType)) # True print(isinstance(Obj.func, FunctionType)) # True print(isinstance(Obj.func, MethodType)) # Flase """ 总结:函数和方法的区别 1.被类调用的是函数,被对象调用的是方法 2.全部参数自己传的是函数,自动传的是方法(比如self) """
# -*- coding: utf-8 -*- """ @Datetime: 2018/12/29 @Author: Zhang Yafei """ """方式一""" # my_singleton.py # # class Singleton(object): # pass # # singleton = Singleton() # # from mysingleton import singleton """方式二:使用装饰器""" # def Singleton(cls): # _instance = {} # # def _singleton(*args, **kargs): # if cls not in _instance: # _instance[cls] = cls(*args, **kargs) # return _instance[cls] # # return _singleton # # # @Singleton # class A(object): # a = 1 # # def __init__(self, x=0): # self.x = x # # # a1 = A(2) # a2 = A(3) """方式三:使用类""" # import threading # import time # # # class Singleton(object): # # def __init__(self): # # time.sleep(1) # pass # @classmethod # def instance(cls, *args, **kwargs): # if not hasattr(Singleton, "_instance"): # Singleton._instance = Singleton(*args, **kwargs) # return Singleton._instance # # # def task(arg): # obj = Singleton.instance() # print(obj) # # # for i in range(10): # t = threading.Thread(target=task,args=[i,]) # t.start() """解决方法:加锁""" # import time # import threading # # # class Singleton(object): # _instance_lock = threading.Lock() # # def __init__(self): # time.sleep(1) # # @classmethod # def instance(cls, *args, **kwargs): # if not hasattr(Singleton, "_instance"): # with Singleton._instance_lock: # if not hasattr(Singleton, "_instance"): # Singleton._instance = Singleton(*args, **kwargs) # return Singleton._instance # # # # # def task(arg): # obj = Singleton.instance() # print(obj) # # for i in range(10): # t = threading.Thread(target=task,args=[i,]) # t.start() # time.sleep(20) # obj = Singleton.instance() # print(obj) """方法四:基于__new__方法""" # # import threading # # class Singleton(object): # _instance_lock = threading.Lock() # # def __init__(self): # pass # # def __new__(cls, *args, **kwargs): # if not hasattr(Singleton, "_instance"): # with Singleton._instance_lock: # if not hasattr(Singleton, "_instance"): # Singleton._instance = object.__new__(cls) # return Singleton._instance # # # obj1 = Singleton() # obj2 = Singleton() # print(obj1,obj2) # # # def task(arg): # obj = Singleton() # print(obj) # # # for i in range(10): # t = threading.Thread(target=task,args=[i,]) # t.start() # """方法五:元类实现单例模式""" import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name obj1 = Foo(‘name‘) obj2 = Foo(‘name‘) print(obj1,obj2)
执行流程
请求到来时候:wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法 -在wsgi_app方法中: 首先将 请求相关+空session 封装到一个RequestContext对象中,即ctx 将ctx交给LocalStack中,再由localstack将ctx添加到local中,local结构: __storage__ = { 1231:{stack:[ctx,]} } -根据请求中的cookie中提取名称为sessionnid对应的值,对cookie进行加密+反序列化,再次赋值给ctx中的session -> 视图函数 - 把session中的数据再次写入到cookie中 -将ctx删除 -结果返回用户浏览器 -断开socket连接 # ctx = RequestContext(self, environ) # self是app对象,environ请求相关的原始数据 # ctx.request = Request(environ) # ctx.session = None # 将包含了request/session的ctx对象放到“空调” { 1232:{ctx:ctx对象} 1231:{ctx:ctx对象} 1211:{ctx:ctx对象} 1111:{ctx:ctx对象} 1261:{ctx:ctx对象} } 视图函数: from flask import reuqest,session request.method 请求结束: 根据当前线程的唯一标记,将“空调”上的数据移除。
主要内容
a. 温大爷:wsig, run_simple() 自动执行__call__方法,__call__方法调用wsgi_app()方法 b. 赵毅: ctx = ReuqestContext(session,request) # 将request和session封装成一个ctx对象 ctx.push() # 通过localstack添加到local(空调)中 c. 刘松:LocalStack,把ctx对象添加到local中 LocalStack的作用:线程标记作为字典的key,字典里面包含key为stack的字典,value为一个列表, localstack的作用就是将这个列表维护成一个stack. d. 空调:Local __storage__={ 1321:{stack:[ctx,]} }
a. 温大爷:wsig b. 赵毅: ctx = ReuqestContext(session=None,request) ctx.push() c. 刘松:LocalStack,把ctx对象添加到local中 d. 空调:Local __storage__={ 1321:{stack:[ctx,]} } e. 郭浩:通过刘松获取ctx中的session,给session赋值(从cookie中读取数据) => open_session
pip3 install flask-session 掌握: - 使用 import redis from flask import Flask,request,session from flask.sessions import SecureCookieSessionInterface from flask_session import Session app = Flask(__name__) # app.session_interface = SecureCookieSessionInterface() # app.session_interface = RedisSessionInterface() app.config[‘SESSION_TYPE‘] = ‘redis‘ app.config[‘SESSION_REDIS‘] = redis.Redis(host=‘140.143.227.206‘,port=6379,password=‘1234‘) Session(app) @app.route(‘/login‘) def login(): session[‘user‘] = ‘alex‘ return ‘asdfasfd‘ @app.route(‘/home‘) def index(): print(session.get(‘user‘)) return ‘...‘ if __name__ == ‘__main__‘: app.run() - 原理: - session数据保存到redis session:随机字符串1:q23asifaksdfkajsdfasdf session:随机字符串2:q23asifaksdfkajsdfasdf session:随机字符串3:q23asifaksdfkajsdfasdf session:随机字符串4:q23asifaksdfkajsdfasdf session:随机字符串5:q23asifaksdfkajsdfasdf - 随机字符串返回给用户,浏览器。 随机字符串 源码: from flask_session import RedisSessionInterface
2. app上下文管理
- - 请求上下文(ctx=RequestContext()):request/session
- - App上下文(app_ctx=AppContext()): app/g
- 程序启动: 两个Local: local1 = { } local2 = { } 两个LocalStack: _request_ctx_stack _app_ctx_stack - 请求到来 对数据进行封装: ctx = RequestContext(request,session) app_ctx = AppContext(app,g) 保存数据: 将包含了(app,g)数据的app_ctx对象,利用 _app_ctx_stack(贝贝,LocalStack())将app_ctx添加到Local中 storage = { 1231:{stack:[app_ctx(app,g),]} } 将包含了request,session数据的ctx对象,利用_request_ctx_stack(刘淞,LocalStack()),将ctx添加到Local中 storage = { 1231:{stack:[ctx(request,session),]} - 视图函数处理: from flask import Flask,request,session,current_app,g app = Flask(__name__) @app.route(‘/index‘) def index(): # 去请求上下文中获取值 _request_ctx_stack request.method # 找小东北获取值 session[‘xxx‘] # 找龙泰获取值 # 去app上下文中获取值:_app_ctx_stack print(current_app) print(g) return "Index" if __name__ == ‘__main__‘: app.run() app.wsgi_app - 结束 _app_ctx_stack.pop() _request_ctx_stack.pop()
1. Flask中g的生命周期? (1) 当一个请求到来时,flask会把app和g封装成一个AppContext对象, (2) 通过_app_ctx_stack = LocalStack()(作用是将local维护成一个栈),将g存放到local中. app_ctx = _app_ctx_stack.top app_ctx.push() _app_ctx_stack.push(self) rv = getattr(self._local, ‘stack‘, None) rv.append(obj) (3) 执行视图函数: g = LocalProxy(partial(_lookup_app_object, ‘g‘)) g.x 通过localProxy对象去local中取g (4) _app_ctx_stack.pop() # 将g清空 - 一次请求声明周期结束 注:两次请求的g不一样 2. g和session一样吗? g只能在同一次请求起作用,请求结束之后就销毁了,昙花一现 但session请求完之后不销毁,不同请求都可以使用 3. g和全局变量一样吗? g是项目启动的时候创建的,且一次请求结束之后删除,可以通过线程标记实现多线程 全局变量多次请求不删除,可以共用,但不能多线程
二、第三方组件
1. 数据库连接池:DBUtils
from DBUtils.PooledDB import PooledDB, SharedDBConnection POOL = PooledDB( creator=pymysql, # 使用链接数据库的模块 maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 maxcached=5, # 链接池中最多闲置的链接,0和None不限制 maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always host=‘127.0.0.1‘, port=3306, user=‘root‘, password=‘0000‘, database=‘flask_code‘, charset=‘utf8‘ ) -注意:使用数据库连接池 from settings import POOL conn = POOL.connection() cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
2.wtforms
-使用 生成html标签 form表单验证 -安装 pip install wtforms -使用 示例:用户登录 用户注册 实时更新:从数据库获取字段,静态字段只在程序扫描第一遍时执行。 解决方法:1.重启 2. 重写form的构造方法,每一次实例化都动态更新需要更新的字段 问题: 1. form对象为什么可以被for循环? 答:变为可迭代对象: class Obj(object): def __iter__(self): # return iter([1,2,3]) yield 1 yield 2 yield 3 obj = Obj() for item in obj: print(item) 2. new方法的返回值决定对象到底是什么? class BAR(object): def __init__(self, cls): self.cls = cls class NEW_OBJ(object): def __new__(cls, *args, **kwargs): # return super(NEW_OBJ, cls).__new__(cls, *args, **kwargs) # <__main__.NEW_OBJ object at 0x000000D445061CF8> # return 123 # 123 # return BAR # <class ‘__main__.BAR‘> # return BAR() # <__main__.BAR object at 0x000000AD77141C50> return BAR(cls) # <__main__.BAR object at 0x0000003BFFA31D68> obj = NEW_OBJ() print(obj) 3. metaclass 1. 创建类时,先执行metaclass(默认为type)的__init__方法 2. 类在实例化时, 执行metaclass(默认为type)的__call__方法,__call__方法的返回值就是实例化的对象 __call__内部调用: - 类.__new__方法:创建对象 _ 类.__init__方法:对象的初始化 class MyType(type): def __init__(self, *args, **kwargs): print(‘MyType的__init__‘) super(MyType, self).__init__(*args, **kwargs) def __call__(cls, *args, **kwargs): print(‘MyType的__call__‘) obj3 = cls.__new__(cls) cls.__init__(obj3) return obj class Obj3(object, metaclass=MyType): x = 123 def __init__(self): print(‘Obj3的__init__‘) def __new__(cls, *args, **kwargs): print(‘Obj3的__new__‘) return object.__new__(cls) def func(self): return 666 源码: -类的创建 type.__init__ -对象的创建: type.__call__ 类.__new__ 类.__init__ Meta - __mro__ - 应用:wtforms中meta使用(meta作用定制csrf token) 钩子函数 class LoginForm(Form): name = simple.StringField( validators=[ validators.DataRequired(message=‘用户名不能为空.‘), ], widget=widgets.TextInput(), render_kw={‘placeholder‘:‘请输入用户名‘} ) pwd = simple.PasswordField( validators=[ validators.DataRequired(message=‘密码不能为空.‘), ], render_kw={‘placeholder‘:‘请输入密码‘} ) def validate_name(self, field): """ 自定义name字段规则 :param field: :return: """ # 最开始初始化时,self.data中已经有所有的值 print(‘钩子函数获取的值‘,field.data) if not field.data.startswith(‘old‘): raise validators.ValidationError("用户名必须以old开头") # 继续后续验证 # raise validators.StopValidation("用户名必须以old开头") # 不再继续后续验证 总结: 记住: https://www.cnblogs.com/wupeiqi/articles/8202357.html 理解: - metaclass - __new__ - __mro__
3.flask-sqlalchemy
pip install flask-sqlalchemy
导入并实例化SQLAlchemy from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() 注意事项: - 必须在导入蓝图之前 - 必须导入models.py
db.init_app(app)
# ##### SQLALchemy配置文件 ##### SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:[email protected]:3306/flask_web?charset=utf8" SQLALCHEMY_POOL_SIZE = 10 SQLALCHEMY_MAX_OVERFLOW = 5
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column from sqlalchemy import Integer,String,Text,Date,DateTime from sqlalchemy import create_engine from chun import db class Users(db.Model): __tablename__ = ‘users‘ id = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=False) depart_id = Column(Integer)
from web import db,create_app app = create_app() app_ctx = app.app_context() # app_ctx = app/g with app_ctx: # __enter__,通过LocalStack放入Local中 db.create_all() # 调用LocalStack放入Local中获取app,再去app中获取配置
from flask import Blueprint from web import db from web import models us = Blueprint(‘us‘,__name__) @us.route(‘/index‘) def index(): # 使用SQLAlchemy在数据库中插入一条数据 # db.session.add(models.Users(name=‘高件套‘,depart_id=1)) # db.session.commit() # db.session.remove() result = db.session.query(models.Users).all() print(result) db.session.remove() return ‘Index‘
4.flask_script
# python manage.py runserver -h 127.0.0.1 -p 8001 from web import create_app from flask_script import Manager app = create_app() manager = Manager(app) if __name__ == ‘__main__‘: # app.run() manager.run()
from web import create_app from flask_script import Manager app = create_app() manager = Manager(app) @manager.command def custom(arg): """ 自定义命令 python manage.py custom 123 :param arg: :return: """ print(arg) if __name__ == ‘__main__‘: # app.run() manager.run()
from web import create_app from flask_script import Manager app = create_app() manager = Manager(app) @manager.option(‘-n‘, ‘--name‘, dest=‘name‘) @manager.option(‘-u‘, ‘--url‘, dest=‘url‘) def cmd(name, url): """ 自定义命令 执行: python manage.py cmd -n wupeiqi -u http://www.oldboyedu.com :param name: :param url: :return: """ print(name, url) if __name__ == ‘__main__‘: # app.run() manager.run()
5. flask-migrate:利用sqlalchemy对数据库中的表进行迁移操作
依赖:flask-script
from flask_script import Manager from flask_migrate import Migrate, MigrateCommand from web import create_app from web import db app = create_app() manager = Manager(app) Migrate(app, db) """ # 数据库迁移命名 python manage.py db init python manage.py db migrate python manage.py db upgrade """ manager.add_command(‘db‘, MigrateCommand) if __name__ == ‘__main__‘: manager.run() # app.run()
6.找到项目使用的所有组件及版本
第一步:pip install pipreqs 第二步: 进入项目目录:pipreqs ./ --encoding=utf-8 从文件中安装包:pip install -r requirements.txt 补充: 虚拟环境导出包:pip freeze>requeriments.txt
7.虚拟环境
方式一:pip3 install virtualenv virtualenv env1 --no-site-packages 方式二::python -m venv mysite_venv 进入script目录: 激活虚拟环境:activate 退出虚拟环境:deactivate
重点:
1. 上下文管理 当请求到来的时候, flask会把请求相关和session相关信息封装到一个ctx = RequestContext对象中, 会把app和g封装到app_ctx = APPContext对象中去, 通过localstack对象将ctx、app_ctx对象封装到local对象中 问题: local是什么?作用? 为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离) localstack是什么?作用 storage = { 1234:{stack:[ctx,]} } localstack将local中的stack中的维护成一个栈 获取数据 通过localproxy对象+偏函数,调用localstack去local中获取响应ctx、app_ctx中封装值 问题:为什么要把ctx = request/session app_ctx = app/g 因为离线脚本需要使用app_ctx 请求结束 调用localstk的pop方法,将ctx和app_ctx移除 2. LocalStack作用? 将local中存储数据的列表维护成一个栈。协程标记作为字典的key,字典里面包含key为stack的字典, value为一个列表,localstack的作用就是将这个列表维护成一个stack. 3. Local中作用? 为每个协程创建一个独立的空间,使得协程对自己的空间中的数据进行操作(数据隔离) 4. threading.local作用? 为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离) 5. LocalProxy作用? 执行视图函数的时候,LocalProxy通过Localstack从local中取数据 6. g的作用? 类似每次请求中的全局变量,但要注意的是g只存在于一次请求中,请求结束之后就销毁了。 7. before_request、after_request 实现原理? 将视图函数添加到一个列表中,然后循环执行其中的函数,after_request将列表reverse一下。 8. 对面向对象的理解? python支持函数式编程和面向对象编程。java和c#只支持面向对象编程。 基础:谈面向对象就要从他的三大特性开始说起,如:封装、继承、多态。 封装: - 方法封装到来类中:某一类功能相似的方法 class File: def file_add():pass def file_update():pass def file_del():pass def file_fetch():pass - 数据封装到对象中 class File: def __init__(self,name,age,email): self.name = name self.age = age self.email = email def file_add():pass def file_update():pass def file_del():pass def file_fetch():pass obj1 = File(‘oldboy‘,19,"[email protected]") obj2 = File(‘oldboy1‘,119,"[email protected]") 应用: - session/request封装到了RequestContext对象中 - app/g封装到了AppContext中 继承:如果多个类中有相同的方法,为了避免重复编写,可以将其放在父类(基类)中。 python支持多继承,继承顺序按__mro__的顺序执行,新式类按广度优先,旧式类类广度优先,Python3都是新式类。先执行左边,在执行右边 class Base(object): def xxxx():pass class File(Base): def __init__(self,name,age,email): self.name = name self.age = age self.email = email def file_add():pass def file_update():pass def file_del():pass def file_fetch():pass class DB(Base): def db_add():pass def db_update():pass def db_del():pass def xxxx():pass def db_fetch():pass 应用: rest framework中的视图类的继承 多态(鸭子模型):天生支持多态,对于参数来说可以传入任何类型的对象,只要保证有想要的send方法即可。 class Msg(object): def send(): pass class WX(object): def send(): pass def func(arg): arg.send() 进阶: __init__,初始化 __new__,创建对象 __call__,对象() __getattr__,对象.xx 且xx不存在 __getattribute__, 对象.xx xx为任何属性 __setattr__. 对象.xx = yy __delattr__, del 对象.xx __setitem__,对象[‘xx‘] = yy __getitem__, 对象[‘xx‘] __delitem__, del 对象[‘xx‘] __mro__,查找成员顺序 __str__, 对象返回值 __repr__, __iter__, 实现此方法,且返回一个迭代器,此对象可迭代 __dict__, 类的成员 __add__, 类 + xx __del__, 对象的生命周期结束之后 高级:metaclass 1. 类创建 class Foo(object):pass Foo = type(‘Foo‘,(object,),{}) 2. 如何指定类由自定义type创建? class MyType(type): pass class Foo(object,metaclass=MyType): # __metaclass__ = MyType # py2 pass Foo = MyType(‘Foo‘,(object,),{}) 3. 默认执行顺序 class Foo(object,metaclass=MyType): pass obj = Foo() class MyType(type): def __init__(self,*args,**kwargs): print(‘111‘) super(MyType,self).__init__(*args,**kwargs) class Base(object, metaclass=MyType): pass class Foo(Base): pass 如果一类自己或基类中指定了metaclass,那么该类就是由metaclass指定的type或mytype创建。 同: class MyType(type): def __init__(self,*args,**kwargs): print(‘111‘) super(MyType,self).__init__(*args,**kwargs) # class Base(object, metaclass=MyType): # pass Base = MyType(‘Base‘,(object,),{}) class Foo(Base): pass 同: class MyType(type): def __init__(self,*args,**kwargs): print(‘111‘) super(MyType,self).__init__(*args,**kwargs) # class Base(object, metaclass=MyType): # pass def with_metaclass(arg): Base = MyType(‘Base‘,(arg,),{}) return Base class Foo(with_metaclass(object)): pass
以上是关于Flask进阶的主要内容,如果未能解决你的问题,请参考以下文章
Python开发实战资料分享:《Flask Web开发实战:入门进阶与原理解析》PDF+源代码
《Flask Web开发实战:入门进阶与原理解析》PDF+源代码 pdf 电子书
我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情