欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python3-开发进阶Flask的基础(3)

程序员文章站 2022-10-04 22:05:41
上篇我们大概简单描述了一下上下文管理,这篇来具体来说说, 一、前奏 1、一个新名词:偏函数 (可以帮你自动传参数) 2、super和执行类的区别? 3、面向对象中特殊方法 setattr/getattr注意事项: 四、栈 基于列表实现的一个栈: 5、Local类 这个是我们自己写的,我们再去看看fl ......

上篇我们大概简单描述了一下上下文管理,这篇来具体来说说,

  1. 上下管理的request
  2. 上下管理的session
  3. 第三方组件:flask-session
  4. pymysql操作数据库  数据库连接池

 

一、前奏

1、一个新名词:偏函数   (可以帮你自动传参数)

import functools   #装饰器用过的模块

def index(a,b):
    return a+b

new_fun=functools.partial(index,666)   #666当作第一个参数

#原来的调用
# ret=index(1,2)
#
# print(ret)
ret=new_fun(1)   #偏函数,帮助开发者自动传递参数
print(ret)

 

2、super和执行类的区别?

class base(object):

    def func(self):
        print('base.func')

class foo(base):
    def func(self):
        #方式一:根据mro的顺序执行方法  
        # super().func()
        #方式二:主动执行base类的方法
        # base.func(self)
        print('foo.func')

obj=foo()
obj.func()
print(obj.__mro__)

 

3、面向对象中特殊方法 setattr/getattr注意事项:

class foo(object):
    def __init__(self):
        #self.duoduo={}    直接定于会发现调用__setattr__方法时,还没有生成会报错
        object.__setattr__(self,'duoduo',{})

    def __setattr__(self, key, value):
        print(key,value,self.duoduo)

obj=foo()
print(obj.duoduo)

 

四、栈

基于列表实现的一个栈:

class stack(object):

    def __init__(self):
        self.data=[]

    def push(self,val):
        self.data.append(val)

    def pop(self):
        return self.data.pop()

_stack=stack()
_stack.push('大娃')
_stack.push('二娃')

print(_stack.pop())
print(_stack.pop())

 

5、local类

try:
    from greenlet import getcurrent as get_ident   #获取协程的唯一标记
except:
    from threading import get_ident   #获取线程的唯一标记

class local(object):

    def __init__(self):
        object.__setattr__(self,'storage',{})

    def __setattr__(self, key, value):
        ident=get_ident()
        if ident not in self.storage:
            self.storage[ident]={key,value}
        else:
            self.storage[ident][key]=value

    def __getattr__(self, item):
        ident=get_ident()
        if ident in self.storage:
            return self.storage[ident].get(item)

这个是我们自己写的,我们再去看看flask中的local类

from flask import globals  #点globals

_request_ctx_stack = localstack()  #点localstack()

self._local = local()   #点local

先看看上面导入的模块:一样的,优先协程,然后线程

python3-开发进阶Flask的基础(3)

 __slots__,只能访问什么属性的范围

python3-开发进阶Flask的基础(3)

 

python3-开发进阶Flask的基础(3)

 

python3-开发进阶Flask的基础(3)

 

6、全局变量只有在初次加载时执行

二、上下文管理 request

1、wsgi   初步处理请求

2 、 __call__方法   执行wsgi_app 

3、ctx=requestcontextsession,request)   再执行  ctx.push()

4、localstack对象 把ctx对象添加到local中

5、local     存数据的时__storage__={'唯一标识':{stack:[ctx,]}}

6、视图函数

 

上下文管理:session 

就一个流程,别的基本上一样,

最后通过localstack获取ctx中的session,给session赋值(从cookie中读取数据)

 

三、flask-session 

先下载第三方的库

pip3 install  flask-session

用法:

import redis
from flask import flask
from flask.sessions import securecookiesessioninterface
from flask_session import session

duo=flask(__name__)

#duo.session_interface=securecookiesessioninterface()
#duo.session_interface=redissessioninterface()
duo.config['session_type']='redis'
duo.config['session_type']=redis.redis(host='11.1.11.1',port=6379,password='123456')
session(duo)

 

我们来看看session里面是什么:

python3-开发进阶Flask的基础(3)

app.session_interface赋值,再来看看sef._get_interface(app)

python3-开发进阶Flask的基础(3)

 

python3-开发进阶Flask的基础(3)

这下我们来说说他的原理:

最开始请求进来的时候,这时是根本没有sesiion,找到他的session,执行open_session

 python3-开发进阶Flask的基础(3)

执行完open_session,就要保存在浏览器上执行save_session

python3-开发进阶Flask的基础(3)

保存好后,下次再来访问:

python3-开发进阶Flask的基础(3)

总结:

  1. session 数据保存到redis   session:随机字符串(每个线程或协程都不一样)
  2. 随机字符串返回给用户

查看源码

from flask_session import redissessioninterface

 

四、数据库连接池

pip3 install dbutils

创建一批连接到连接池,供所有线程共享使用。

import time
import pymysql
import threading
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='123', database='db', charset='utf8' ) def func(): # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise toomanyconnections异常 # 否则 # 则优先去初始化时创建的链接中获取链接 steadydbconnection。 # 然后将steadydbconnection对象封装到pooleddedicateddbconnection中并返回。 # 如果最开始创建的链接没有链接,则去创建一个steadydbconnection对象,再封装到pooleddedicateddbconnection中并返回。 # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。 conn = pool.connection() cursor = conn.cursor(pymysql.cursors.dictcursor) #pymsql cursor.execute('select * from tb1') result = cursor.fetchall() conn.close() func()

注意:

  使用数据库要用连接池

    封装sqlhelper