多app应用
from flask import Flask
from werkzeug.serving import run_simple
from werkzeug.middleware.dispatcher import DispatcherMiddleware
app01 = Flask('app01')
app02 = Flask('app02')
@app01.route('/index')
def index():
return "app01"
@app02.route('/index2')
def index2():
return "app2"
dm = DispatcherMiddleware(app01, {'/sec': app02, })
if __name__ == '__main__':
run_simple('localhost', 5000, dm)
-内部如何执行
1 请求来了,会执行dm(environ,start_response)
2 dm的__call__ 根据请求的地址,拿到不同的app,执行app(environ,start_response)--->Flask的__call__
flask-script
1.flask 的一个第三方插件,完成像django 的 python py文件名 runserver 命令操作
2.下载
pip3 install flask-script
3.自定制命令
from flask import Flask
from flask_script import Manager
app = Flask('app01')
manager = Manager(app)
@manager.command
def custom(arg):
"""
自定义命令
python manage.py custom 123
"""
print(arg)
@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
"""
自定义命令(-n也可以写成--name)
执行: python manage.py cmd -n lqz -u http://www.oldboyedu.com
执行: python manage.py cmd --name lqz --url http://www.oldboyedu.com
"""
print(name, url)
@app.route('/index')
def index():
return "app01"
if __name__ == '__main__':
manager.run()
4.django 中自定义命令
-第一步:在app中新建包:management
-第二步:在management下新建包:commands
-第三步:commands新建py文件,py文件名就是命令名 init.py
-第四步:init.py写入
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--name', type=str)
def handle(self, *args, **options):
name = options['name']
-执行这个命令的逻辑是什么
python manage.py init --name=lqz
导出项目依赖
1.使用真实环境导出依赖,会把所有都导出,可能会有问题,导出太多
- 项目依赖 pip3 install pipreqs
- 生成依赖文件:pipreqs ./ --encoding=utf8
- 安装依赖文件:pip3 install -r requirements.txt
函数和方法
1.函数就是普通函数,有几个值就要传几个值
-方法[面向对象]是绑定给对象,类,绑定给谁谁来调用,会自动传值,谁来调用就会把谁传入
-总结:只要能自动传值,就是方法,有几个值传几个值就是函数
def add(a, b):
return a + b
class Person:
def speak(self):
print('人说话')
@classmethod
def test(cls):
print('类的绑定方法')
@staticmethod
def ttt():
print('static')
p = Person()
from types import MethodType, FunctionType
print(isinstance(add, MethodType))
print(isinstance(add, FunctionType))
print(isinstance(p.speak, MethodType))
print(isinstance(p.speak, FunctionType))
print(isinstance(Person.speak, FunctionType))
print(isinstance(Person.speak, MethodType))
Person.speak(p)
print(isinstance(Person.test, FunctionType))
print(isinstance(Person.test, MethodType))
print(isinstance(p.test, FunctionType))
print(isinstance(p.test, MethodType))
Person.test()
print(isinstance(p.ttt, FunctionType))
print(isinstance(p.ttt, MethodType))
偏函数
-python内置给咱们一个偏函数,可以把函数包裹一下,提前传参
from functools import partial
def add(a, b, c):
return a + b + c
res = partial(add, 4, 5)
print(res)
print(res(6))
threading.local
1.threading.local 对象
-多个线程操作同一个变量,如果不加锁,会出现数据错乱问题
2.作用
线程变量,意思是threading.local中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。threading.local为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量
2.1但是 多个线程同时操作 threading.local 对象 就不会出现数据错乱
-java:ThreadLocal
-python:threading.local
3.使用local
from threading import Thread,get_ident
from threading import local
import time
lqz = local()
def task(arg):
lqz.value = arg
time.sleep(0.1)
print('第:%s条线程的值为:%s'%(get_ident(),lqz.value))
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
自定义local支持线程和协程
1.flask 的request,和session 都是全局的,但是我们在不同的视图函数中使用的 是正对于当前这次请求的对象,它的底层就是基于local写的
-flask部署支持多进程线程架构,也支持协程架构,flask内部重写了local,让它支持线程和协程
2.local的本质是如何实现的
-变量对其他线程而言是隔离的
-local: {'线程id号':{}}
-设置值:
-线程1:local.val='lqz' ---> {'线程1id号':{val:lqz},}
-线程2:local.val='pyy' ---> {'线程1id号':{val:lqz},'线程2id号':{val:pyy},}
-取值:
-线程1:print(local.val) ---->l={'线程1id号':{val:lqz},'线程2id号':{val:pyy},}--》先当前线程的id号:get_ident() l[get_ident(线程1)]['val']
-线程2:print(local.val) ---->l={'线程1id号':{val:lqz},'线程2id号':{val:pyy},}--》先当前线程的id号:get_ident() l[get_ident(线程2)]['val']
1 通过字典自定义threading.local
from threading import get_ident, Thread
import time
storage = {}
def set(k, v):
ident = get_ident()
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)
v = get('val')
time.sleep(0.01)
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 = {}
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')
time.sleep(0.01)
print(v)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
3 重写类的 __setattr__ __getattr
from threading import get_ident, Thread
import time
class Local(object):
storage = {}
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()
def task(arg):
obj.val = arg
v = obj.val
time.sleep(0.01)
print(v)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
4 每个对象有自己的存储空间(字典)
取值:对象.属性,如果没有属性会触发 __getattr__
设置值:对象.属性='值',如果属性不存在,会触发 __setattr__
如果属性有,直接就拿回来了
from threading import get_ident, 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}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
obj = Local()
def task(arg):
obj.val = arg
v = obj.val
time.sleep(0.01)
print(v)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
5 兼容线程和协程
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}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
obj = Local()
def task(arg):
obj.val = arg
v = obj.val
time.sleep(0.01)
print(v)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
flask 自定义的local,支持线程和协程
class Local(object):
def __init__(self):
object.__setattr__(self, "__storage__", {})
object.__setattr__(self, "__ident_func__", get_ident)
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
flask请求上下文分析
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
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)
def push(self):
_request_ctx_stack.push(self)
if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
if self.url_adapter is not None:
self.match_request()
def push(self, obj):
rv = getattr(self._local, "stack", None)
if rv is None:
rv = []
self._local.stack = rv
rv.append(obj)
return rv
视图函数中:print(request.method)
def __getattr__(self, name):
return getattr(self._get_current_object(), name)
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)
请求上下文执行流程
请求上下文执行流程(ctx):
-0 flask项目一启动,有6个全局变量
-_request_ctx_stack:LocalStack对象
-_app_ctx_stack :LocalStack对象
-request : LocalProxy对象
-session : LocalProxy对象
-1 请求来了 app.__call__()---->内部执行:self.wsgi_app(environ, start_response)
-2 wsgi_app()
-2.1 执行:ctx = self.request_context(environ):返回一个RequestContext对象,并且封装了request(当次请求的request对象),session,flash,当前app对象
-2.2 执行: ctx.push():RequestContext对象的push方法
-2.2.1 push方法中中间位置有:_request_ctx_stack.push(self),self是ctx对象
-2.2.2 去_request_ctx_stack对象的类中找push方法(LocalStack中找push方法)
-2.2.3 push方法源码:
def push(self, obj):
rv = getattr(self._local, "stack", None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv
-3 如果在视图函数中使用request对象,比如:print(request)
-3.1 会调用request对象的__str__方法,request类是:LocalProxy
-3.2 LocalProxy中的__str__方法:lambda x: str(x._get_current_object())
-3.2.1 内部执行self._get_current_object()
-3.2.2 _get_current_object()方法的源码如下:
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
-3.2.3 _lookup_req_object函数源码如下:
def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)
-3.2.4 所以:print(request) 实质上是在打印当此请求的request对象的__str__
-4 如果在视图函数中使用request对象,比如:print(request.method):实质上是取到当次请求的reuquest对象的method属性
-5 最终,请求结束执行: ctx.auto_pop(error),把ctx移除掉
其他的东西:
-session:
-请求来了opensession
-ctx.push()---->也就是RequestContext类的push方法的最后的地方:
if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
-请求走了savesession
-response = self.full_dispatch_request() 方法内部:执行了before_first_request,before_request,视图函数,after_request,savesession
-self.full_dispatch_request()---->执行:self.finalize_request(rv)-----》self.process_response(response)----》最后:self.session_interface.save_session(self, ctx.session, response)
-请求扩展相关
before_first_request,before_request,after_request依次执行
-flask有一个请求上下文,一个应用上下文
-ctx:
-是:RequestContext对象:封装了request和session
-调用了:_request_ctx_stack.push(self)就是把:ctx放到了那个位置
-app_ctx:
-是:AppContext(self) 对象:封装了当前的app和g
-调用 _app_ctx_stack.push(self) 就是把:app_ctx放到了那个位置
-g是个什么鬼?
专门用来存储用户信息的g对象,g的全称的为global
g对象在一次请求中的所有的代码的地方,都是可以使用的
-代理模式
-request和session就是代理对象,用的就是代理模式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)