阅读flask源码3:仿写Local,LocalStack

2024-03-16 22:08

本文主要是介绍阅读flask源码3:仿写Local,LocalStack,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们上篇分析了上下文压入栈,出栈的大致流程,现在我们要问,flask是怎么实现的呢?准备来说,Local是怎么管理不同请求对象的,LocalProxy是怎么代理的。因为flask源码太复杂,今天我们自己一步一步实现类似于Local,LocalProxy的代码。通过自己实现,我们学会用代理模式,学会python的魔法方法__setattr__,getattr

class A(object):def spam(self, x):print('A.spam')def foo(self):print('A.foo')# 简单的代理
class AProxy(object):def __init__(self):self._a = A()def spam(self,x):print('B1.spam')return self._a.spam(x)def foo(self):print('B1.foo')return self._a.foo()def bar(self):print('B1.bar')b1 = AProxy()
b1.spam(1)
b1.foo()
b1.bar()

这里的b1,是一个对象,我们访问b1.spam(1),它会返回类A的一个实例的方法。b1.foo()也同理。

这个代理的问题是,我们写代理的时候,要先知道被代理的类A有哪些方法,下面我们实现一种更通用的代理。

class A(object):def spam(self, x):print('A.spam')def foo(self):print('A.foo')# 简单的代理
class AProxy(object):def __init__(self):self._a = A()self.name = ''def __getattr__(self,name):return getattr(self._a,key)def bar(self):print('B1.bar')b1 = AProxy()
b1.spam(1)
b1.foo()
b1.bar()

上面这个代理,比第一个就抽象了,这晨用__getattr__实现了什么呢?只要你访问AProxy没有的方法,它就会去__getattr__中找,这个函数实现了你给一个函数名,它会给你被代理对象的函数。这里是一个抽象。

上面这个函数,只是实现了属性,方法的访问,却不能给它赋值。

class A(object):def __init__(self):self.log = ''def spam(self, x):print('A.spam')def foo(self):print('A.foo')# 简单的代理
class AProxy(object):def __init__(self):self._a = A()self.name = ''def __getattr__(self,name):return getattr(self._a,key)def __setattr__(self,name,value):return setattr(self._a,name,value)def bar(self):print('B1.bar')b1 = AProxy()
b1.name = '我是AProxy的一个实例'
b1.log = '我是A的一个实例'

这个代理就比前一个更好用了,因为它可以给A的实例间接赋值。我们调用b1.log,这个时候AProxy没有这个属性,这时就去__setattr__中找,把log,'我是A的一个实例’作为实参,传给__setattr__。

当然这个代理也有些问题,就是它还不够抽象,它现在只能代理类A,如果我们希望它还能代理其它类怎么办呢?

改进如下:

class A(object):def __init__(self):self.log = ''def spam(self, x):print('A.spam')def foo(self):print('A.foo')# 简单的代理
class AProxy(object):def __init__(self,object):self._a = objectself.name = ''def __getattr__(self,name):return getattr(self._a,key)def __setattr__(self,name,value):return setattr(self._a,name,value)def bar(self):print('B1.bar')
a1 = A
b1 = AProxy(a1)
b1.name = '我是AProxy的一个实例'
b1.log = '我是A的一个实例'

这里通过一个给AProxy传参初始化,可以拿到不同的实例代理。

有了上面这些基础,现在我们模仿Local,LocalProxy来写一个代理:

class Request(object):def __init__(self):self.url = 'tanliang.com'class User(object):def __init__(self):self.owner = 'tanliang'class Local:def __init__(self):self._objs = {}self._objs['request'] = Request()self._objs['user'] = User()def __getattr__(self, name):print('Local.__getattr__')return self._objs[name]def __call__(self, name):return LocalProxy(self, name)class LocalProxy(object):def __init__(self, local, name):self._local = localself._name = namedef _get_current_obj(self):print('_get_current_obj')return getattr(self._local, self._name)def __getattr__(self, name):print('SpamProxy.__getattr__')return getattr(self._get_current_obj(), name)def __setattr__(self, name ,value):if name.startswith('_'):super().__setattr__(name, value)else:setattr(self._obj, name, value)def __delattr__(self, name):print('SpamProxy.__delattr__')if name.startswith('_'):super().__delattr__(name)else:print('SpamProxy', name)delattr(self._obj, name)l = Local()request = l('request')
print(request)
print(request.url)user = l('user') 
print(user.owner)

这里l是一个Local实例,request是一个代理对象,LocalProxy的实例,因为Local实现了__call__方法。当我们访问request.url时,会发生什么呢?先找到__getattr__,然后把url作为参数传给getattr。可是这个时候还没有拿到“当前对象”。self.__get_current_obj()就是拿当前对象的,最后能过Local的__getattr__拿到request对象。

这篇关于阅读flask源码3:仿写Local,LocalStack的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/816865

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Python 安装和配置flask, flask_cors的图文教程

《Python安装和配置flask,flask_cors的图文教程》:本文主要介绍Python安装和配置flask,flask_cors的图文教程,本文通过图文并茂的形式给大家介绍的非常详细,... 目录一.python安装:二,配置环境变量,三:检查Python安装和环境变量,四:安装flask和flas

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

Flask 验证码自动生成的实现示例

《Flask验证码自动生成的实现示例》本文主要介绍了Flask验证码自动生成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录生成图片以及结果处理验证码蓝图html页面展示想必验证码大家都有所了解,但是可以自己定义图片验证码

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架

Flask解决指定端口无法生效问题

《Flask解决指定端口无法生效问题》文章讲述了在使用PyCharm开发Flask应用时,启动地址与手动指定的IP端口不一致的问题,通过修改PyCharm的运行配置,将Flask项目的运行模式从Fla... 目录android问题重现解决方案问题重现手动指定的IP端口是app.run(host='0.0.

Python结合Flask框架构建一个简易的远程控制系统

《Python结合Flask框架构建一个简易的远程控制系统》这篇文章主要为大家详细介绍了如何使用Python与Flask框架构建一个简易的远程控制系统,能够远程执行操作命令(如关机、重启、锁屏等),还... 目录1.概述2.功能使用系统命令执行实时屏幕监控3. BUG修复过程1. Authorization