阅读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智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易