首页 > 编程语言 >flask源码分析

flask源码分析

时间:2023-04-06 19:33:19浏览次数:46  
标签:分析 form flask ctx self request 源码 print local

目录

请求上下文分析(源码:request原理)

导出项目的依赖

之前的pip freeze > requeirments.txt 会把当前解释器环境下的所有第三方依赖都导出来

使用第三方模块,更精确的导出依赖 pipreqs
    第一步:安装 pip3 install pipreqs
    第二步:使用命令,导出项目依赖   pipreqs ./ 
        -win由于编码问题会出错:pipreqs ./ --encoding=utf8
        -mac,linx没有问题

    第三步:就会在项目根路径下生成:requirements.txt

函数和方法

方法:只要会自动串珠的,就是方法
函数:有几个值就要传几个值,否则报错
 
函数就是普通的函数,有几个参数就要传几个参数
方法:绑定给对象的方法,绑定给类的方法,绑定给谁,由谁来调用,会自动把自身传入
类的绑定方法:类来调用会把类作为第一个参数自动传入,对象来调用,会把产生对象的类作为第一个参数传入
对象的绑定方法:对象来调用会把对象作为第一个参数传入,类来调用他就会变成普通函数,有几个值传几个值,没有自动传值了
  
MethodType		检查一个对象,是不是方法
FunctionType	检查一个对象,是不是函数
isinstance 		判断一个对象,是不是一个类的对象
issubclass 		判断一个类,是不是另一个类的子类

from types import MethodType, FunctionType


class Foo(object):
    def fetch(self):
        pass

    @classmethod
    def test(cls):
        pass

    @staticmethod
    def test1():
        pass


# a=Foo()
# print(isinstance(a,Foo))
# print(isinstance('a',Foo))
#
# class Foo2(Foo):
#     pass
# class Foo3():
#     pass
# print(issubclass(Foo2,Foo))
# print(issubclass(Foo3,Foo))


def add():
    pass


# 类来调用对象的绑定方法,
print(isinstance(Foo.fetch, MethodType))  # False  类来调用对象的绑定方法,该方法就变成了普通函数
obj = Foo()
print(isinstance(obj.fetch, MethodType))  # True    对象来调用自己的绑定方法,fetch就是方法
print(isinstance(Foo.fetch, FunctionType))  # True   类来调用对象的绑定方法,该方法就变成了普通函数

print(isinstance(add, FunctionType))  # True  就是个普通函数
print(isinstance(add, MethodType))  # False  就是个普通函数


print(isinstance(Foo.test, MethodType))  # True test 是绑定给类的方法,类来调用,就是方法

print(isinstance(obj.test, MethodType))  # True  对象调用类的绑定方法,还是方法

print(isinstance(Foo.test1, MethodType))  # False 是普通函数
print(isinstance(obj.test1, MethodType))  # False 是普通函数
print(isinstance(obj.test1, FunctionType))  # True,静态方法,就是普通函数,对象和类都可以调用,有几个值就传几个值

threading.local对象

并发编程时,多个线程操作同一个变量,会出现并发安全的问题,所以需要加锁

使用local对象,多线并发操作时,不需要加锁,不会出现数据错乱threading.local

其他语言中也有这个东西ThreadLocal,java中面试会被经常问到,python没人问

本质原理:
    多个线程修改同一个数据,赋值多份变量给每个线程用,为每个线程开辟一块空间进行数据存储,每个线程操作的是自己那部分数据

偏函数

其实就函数可以提前传值

from functools import partial
def add(a,b,c):
    return a+b+c


# print(add(2,3,4))  # 传少了报错

# 现在只有一个参数,后面的俩参数,需要过一会才知道
# 借助于偏函数,先提前给他把第一个参数传入,后面知道了后面俩参数,再传后面俩

add=partial(add,2)
#
# # 干了很多事
#
print(add(3,4))

flask整个生命执行流程(1.1.4版本为例)

# 请求来了---》app()----->Flask.__call__--->self.wsgi_app(environ, start_response)
    def wsgi_app(self, environ, start_response):
        # environ:http请求拆成了字典
        # ctx对象:RequestContext类的对象,对象里有:当次的requets对象,app对象,session对象
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                #ctx RequestContext类 push方法
                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)
            
            
            
            
            
  # RequestContext :ctx.push
 def push(self):
		# _request_ctx_stack = LocalStack() ---》push(ctx对象)--》ctx:request,session,app
        _request_ctx_stack.push(self)
		#session相关的
        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()
            
            
            
# LocalStack()  push --->obj 是ctx对象
    def push(self, obj):
        #self._local  _local 就是咱们刚刚自己写的Local的对象---》LocalStack的init初始化的_local---》self._local = Local()---》Local对象可以根据线程协程区分数据 
        rv = getattr(self._local, "stack", None)
        # 一开始没有值
        if rv is None:
            rv = []
            self._local.stack = rv  # self._local.stack 根据不同线程用的是自己的数据
        rv.append(obj)  # self._local.stack.append(obj)
        # {'线程id号':{stack:[ctx]},'线程id号2':{stack:[ctx]}}
        return rv
    
    
    
 # 再往后执行,就会进入到路由匹配,执行视图函数
	# request = LocalProxy(partial(_lookup_req_object, "request"))
    # LocalProxy 代理类---》method---》代理类去当前线程的stack取出ctx,取出当时放进去的request
	视图函数中:print(request.method)
    
    
# print(request) 执行LocalProxy类的__str__方法
# request.method 执行LocalProxy类的__getattr__
    def __getattr__(self, name): #name 是method
        # self._get_current_object() 就是当次请求的request
        return getattr(self._get_current_object(), name)
    
    
 # LocalProxy类的方法_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__)
            
            
            
 # self.__local 是在 LocalProxy 类实例化的时候传入的local

# 在这里实例化的:request = LocalProxy(partial(_lookup_req_object, "request"))
# local 是 partial(_lookup_req_object, "request")

#_lookup_req_object ,name=request
def _lookup_req_object(name):
    top = _request_ctx_stack.top  # 取出了ctx,是当前线程的ctx
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    return getattr(top, name)  #从ctx中反射出request,当次请求的request

wtforms

# django 有forms组件
	- 生成前端模板
    - 校验数据
    - 渲染错误信息
 
# flask 中使用第三方的wtforms 实现像django的forms一样的功能
	- 第一步:导入,定义一个类,继承forms
    -第二步:模板中, for循环生成模板
    -第三步:视图函数中,使用form校验数据


    
# py代码
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')

app.debug = True


class LoginForm(Form):
    # 字段(内部包含正则表达式)
    name = simple.StringField(
        label='用户名',
        validators=[
            validators.DataRequired(message='用户名不能为空.'),
            validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
        ],
        widget=widgets.TextInput(), # 页面上显示的插件
        render_kw={'class': 'form-control'}

    )
    # 字段(内部包含正则表达式)
    pwd = simple.PasswordField(
        label='密码',
        validators=[
            validators.DataRequired(message='密码不能为空.'),
            validators.Length(min=8, message='用户名长度必须大于%(min)d'),
            validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
                              message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')

        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )



@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        form = LoginForm()
        return render_template('login.html', form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print('用户提交数据通过格式验证,提交的值为:', form.data)
        else:
            print(form.errors)
        return render_template('login.html', form=form)

if __name__ == '__main__':
    app.run()

# html代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<form method="post" novalidate>
    <p>{{form.name.label}}: {{form.name}} {{form.name.errors[0] }}</p>

    <p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p>
    <input type="submit" value="提交">
</form>
</body>
</html>

标签:分析,form,flask,ctx,self,request,源码,print,local
From: https://www.cnblogs.com/zhanghong1229/p/17293922.html

相关文章

  • flask4
    今日内容1请求上下文分析(源码:request原理)1.1导出项目的依赖#之前pipfreeze>requirments.txt把当前解释器环境下的所有第三方依赖都导出来#使用第三方模块,更精确的导出依赖pipreqs 第一步:安装pip3installpipreqs第二步:使用命令,导出项目依赖pipreqs./......
  • 六轴桌面机械臂 上位机(PC)源码与下位机(单片机)源码
    六轴桌面机械臂上位机(PC)源码与下位机(单片机)源码YID:1690609972944148......
  • 安卓项目源码 校园跑腿帮APP android stu dio项目 附源码
    全新安卓项目源码校园跑腿帮APPandroidstudio项目附源码,安装包,说明,录屏,截屏。Materialdesign风格设计,支持登录注册,任务发布,修改,上拉加载,下拉刷新,一键换肤等。YID:7598641395930165......
  • MySQL(十二)索引使用的情况分析
    索引使用的情况分析数据准备创建表student_info、courseCREATETABLE`student_info`(`id`intNOTNULLAUTO_INCREMENT,`student_id`intNOTNULL,`name`varchar(20)DEFAULTNULL,`course_id`intNOTNULL,`class_id`intDEFAULTNULL,`create_tim......
  • 简单分析
    流量监控,例如过滤出“8.8.8.8”的IP流量yuminstallepel-releaseiftopiftop-ienp2s0f0-N-P-F8.8.8.8/32ntcpdump,例如过滤出"8.8.8.8:3636"的数据包tcpdump-ienp2s0f0host8.8.8.8anddstport3636-nntcpdump多个IP进行抓包tcpdump-ienp2s0f0host1.1......
  • 详细分析国外主机的性能和稳定性如何?
    详细分析国外主机的性能和稳定性如何?主机是一个网站的重要组成部分,因此选择一个高性能、高稳定性的主机对网站的运营至关重要。国外主机市场具有多样化的选择,本文将从性能和稳定性两个方面分析国外主机的表现。一、性能1、存储性能存储是指主机的硬盘容量和速度,对于网站来说,存......
  • BiSyn GAT+:用于基于方面的情绪分析的双语法感知图形注意力网络
    基于方面的情绪分析(ABSA)是一种细粒度的情绪分析任务,旨在调整方面和相应的情绪,以进行特定方面的情绪极性推断。这很有挑战性,因为一个句子可能包含多个方面或复杂的(例如,条件关系、协调关系或对抗关系)。近年来,利用图神经网络挖掘依赖语法信息已成为最流行的趋势。尽管它取得了成功,但......
  • Unable to handle kernel NULL pointer dereference at virtual address 分析
    引用:https://blog.csdn.net/agave7/article/details/119875023虽然问题不一样,但是分析问题的方法是一致的。UnabletohandlekernelNULLpointerdereferenceatvirtualaddress分析现象[136.847780]br-lan:receivedpacketoneth0.1withownaddressassourceadd......
  • 第十二章---电商产品评论数据情感分析
    1.评论去重的代码importpandasaspdimportreimportjieba.possegaspsgimportnumpyasnp#去重,去除完全重复的数据reviews=pd.read_csv("./reviews.csv")reviews=reviews[['content','content_type']].drop_duplicates()content=reviews......
  • Exp4-恶意代码分析 20202211王宏韬
    目录1.实验后回答问题(1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么。请设计下你想监控的操作有哪些,用什么方法来监控。(2)如果已经确定是某个程序或进程有问题,你有什么工具可以进一步得到它的哪些信息。2.实验总结与体会......