本文完整代码请查看github项目:advance-python,或者直接访问链接:

https://github.com/Jackpopc/advance-python/blob/master/6-Proxy.ipynb

前言

学会使用一门编程语言来完成一项功能非常容易,尤其是Python、Go这些脚本语言,也许对于有一定编程基础的同学而言只需要一周或者一天时间。但是如果要想让写的代码变得更加简洁易读、执行效率更高、可扩展性更好,那么就需要超越编程语言之外的知识,这就是设计模式

在前面文章中,我介绍了一种比较常用的一种设计模式:单例模式。其实软件设计模式有非常多,代理模式、桥接模式、适配器、享元、工厂模式等。这些设计模式有的用的较多,有的在特定场景下才会用到,我会挑选个别应用场景较多的讲解一下。本文的要讲的就是代理模式,话不多说,下面开始代理模式的介绍及在Python中代理模式的实现方式。

代理模式

提到代理这个词汇,应该很多人都不陌生,甚至会有很多人用过。在编程语言之外,我们所接触的代理主要是在网络通信方面会涉及。当我们的网络不能直接与目标主机进行通信时,例如我们不能直接访问Google、Facebook,我们可以通过搭建代理服务器的方式实现我们所用的网络与目标主机之间的通信,这就是网络中代理的概念。用一句话来概括就是:允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接

之所以开始便讲解网络代理,是因为代理模式和网络代理有着很多相似的特点,而我们日常中接触更多的是网络代理,这样类比一下能够有助于大家的理解。

代理模式中,我们作为访问者就相当于编程语言中调用的实体,目标主机就相当于被调用的实体,它们二者直接不产生直接联系,而是通过中间的代理服务器(代理实体)来实现二者的间接联系。

代理模式的作用

一个概念的产生,自然有它的价值存在,代理模式也是这样,简而言之,概括代理模式的作用如下:

当我们访问一个实体考虑到安全等因素不方便时,代理可以为这个实体提供一个替代者,来控制它的访问权限和访问内容。

通俗的来讲,代理模式就如同一个"过滤器",它不实现具体功能,具体功能由被调用的实体来实现,代理实现的是对调用的控制功能,它能够允许或者拒绝调用实体对被调用实体的访问。

举个例子,我们访问一个具备敏感数据时,需要提供一个验证信息,比如,用户名、密码,代理模式完成的是更具访问者提供的用户名和密码来判断是否允许它进一步调用实体的功能。

代理模式的适用场景 一个设计模式,只有当它有了应用场景,它才具备存在的价值。代理模式有很多可以使用的场景,主要分为如下几类:

远程代理:为一个对象的地址空间提供局部代表。 虚拟代理:根据需要来创建开销较大的对象。 保护代理:用于对象应该具有不同访问权限的场景,控制对原始对象的访问。 智能指引:取代简单的指针,它在访问对象时执行一些附加操作。 -- 引自《设计模式:可复用面向对象软件的基础》

Python代理模式

代理模式在Java、C++中使用较多,可以用于虚拟代理和远程代理。由于Python这门语言相对简单,在企业中也常用于算法模块的验证,在一些大型系统很少会采用Python这门语言,因此,在软件设计模式方面考虑相对较少。但是,我认为,养成一个良好的软件设计思维,对日常开发和维护也具有非常多的好处,能够让开发效率更高,能够让代码可靠性更高,能够让后期维护成本更低。

在开发代码实现Python代理模式之前,我们首先来设定一个应用场景,这样才能够更加体现它的价值,同时让各位更加容易理解。

场景设定

假如,我们现在想了解一个班级的情况,主要包括两点:人数和学习成绩。

当我们想要了解这个班级的人数时,这个数据不敏感,不涉及隐私,因此可以直接访问。但是,当我们想查询特定某个学生成绩时,这样就涉及隐私信息,需要提供对应学生的姓名(user_name),访问的密码(password)。

需求分析

针对这个场景,我们可以先分析一下,访问者就如同上述图中的客户端(Client),获取班级人数、成绩这些实际的功能是由实体对象实现,也就是图中的RealSubject。Client与RealSubject之间不能直接通信,它们只能通过中间的代理(Proxy)进行通信。而Proxy主要的职责就相当于一个控制开关,如果Client要访问班级人数,Proxy会检查这项数据所需要的权限,然后发现班级人数是非敏感数据可以直接访问,那么它会调用实体对象中的方法,返回结果。如果Client要访问某个学生的成绩,Proxy会检查这项数据是敏感数据,需要提供用户名和密码,如果Client提供的正确,则允许访问,否则拒绝访问。

编程实践

第一步,我们自定义一个异常处理类,当我们要访问的用户不在班级成绩列表时,则抛出异常,

class NotFindError(Exception): def __init__(self, msg): self.msg = msg

第二步,实现实体类,实体类实现了具体的功能,针对这个场景就两个方法:获取班级人数、获取指定学生的成绩,

class RealSubject(object): def __init__(self): self.score = { "张三": 90, "李四": 59, "王二": 61 }​ def num_students(self): num = len(self.score.keys()) print("The number of students is {num}".format(num=num))​ def get_score(self, user_name): _score = self.score.get(user_name) print("The score of {user} is {score}".format(user=user_name, score=_score))

第三步,实现代理(Proxy),它通过对应功能的访问权限来确定是接受这个访问,还是拒绝这个访问,

注意:在这个示例中,我把密码直接写在初始化方法中,实际的项目是不允许这样的,不能把密码写在代码中,另外也不能使用明文密码,需要使用加密工具对明文密码进行加密。

class Proxy(object): def __init__(self): self.default_passwd = "9l0skjlsa" self.real_subject = RealSubject()​ def num_students(self): self.real_subject.num_students()​ def get_score(self, user_name): print("You are visiting {} score ...".format(user_name)) passwd = input("Please input password : ") if passwd == self.default_passwd: if user_name in self.real_subject.score.keys(): return self.real_subject.get_score(user_name) else: raise NotFindError("The student you are visiting not found.") else: raise ValueError("The password you provided is wrong!")

然后就是实现Client来调用对应的功能,为了测试上述代理的功能,使用3个测试样例,

  1. 密码错误,用户名正确;
  2. 密码正确,用户名错误;
  3. 密码正确,用户名正确;

密码错误,用户名正确

def client(): proxy = Proxy() proxy.get_score("张三") client()​# shellYou are visiting 张三 score ...Please input password : kdksla # 输出ValueError: The password you provided is wrong!

密码正确,用户名错误

def client(): proxy = Proxy() proxy.get_score("李三") client()​# shellYou are visiting 张三 score ...Please input password : 9l0skjlsa​# 输出NotFindError: The student you are visiting not found.

密码正确,用户名正确

def client(): proxy = Proxy() proxy.get_score("李四") client()​# shellYou are visiting 张三 score ...Please input password : 9l0skjlsa​# 输出The score of 李四 is 59

本讲完整代码如下,

class NotFindError(Exception): def __init__(self, msg): self.msg = msg​​class RealSubject(object): def __init__(self): self.score = { "张三": 90, "李四": 59, "王二": 61 }​ def num_students(self): num = len(self.score.keys()) print("The number of students is {num}".format(num=num))​ def get_score(self, user_name): _score = self.score.get(user_name) print("The score of {user} is {score}".format(user=user_name, score=_score))​​class Proxy(object): def __init__(self): self.default_passwd = "9l0skjlsa" self.real_subject = RealSubject()​ def num_students(self): self.real_subject.num_students()​ def get_score(self, user_name): print("You are visiting {} score ...".format(user_name)) passwd = input("Please input password : ") if passwd == self.default_passwd: if user_name in self.real_subject.score.keys(): return self.real_subject.get_score(user_name) else: raise NotFindError("The student you are visiting not found.") else: raise ValueError("The password you provided is wrong!")​​def client(): proxy = Proxy() proxy.get_score("张三")​client()

福利

我在公众号分享了Python、机器学习、计算机视觉、强化学习等领域相关的学习资源、电子文档。此外,还整理了一些高效的实用工具,如果需要可以关注公众号【平凡而诗意】,回复相应关键字获取~

python os.remove拒绝访问_「进阶Python」第八讲:代理模式相关推荐

  1. python微信自动打卡_「微信辅助」吃鸡再也不怕了,Python用wxpy实现微信自动回复...

    我是程序员小小叶,为大家带来原创精彩技术内容. 首先安装wxpy. pip install wxpy优点:相比itchat封装了接口,使用较为方便.注意事项:wxpy 支持 Python 3.4-3. ...

  2. python从小到大的顺序输出_「小白专栏」Python中使用for循环,为什么输出结果不是按顺序?...

    欢迎各位小哥哥小姐姐阅读本的文章,对大家学习有帮助,请点赞加关注哦!!!!!!!!!! 您的点赞和关注将是我持续更新的动力呢.^v^ 有不懂的问题可以私聊我哦! 前言 如图,为什么输出的不是按Jen, ...

  3. python 深度学习源码_「深度学习」用TensorFlow实现人脸识别(附源码,快速get技能)...

    本文将会带你使用python码一个卷积神经网络模型,实现人脸识别,操作难度比较低,动手跟着做吧,让你的电脑认出你那帅气的脸. 由于代码篇幅较长,而且最重要的缩进都没了,建议直接打开源码或者点击分享-& ...

  4. python 搜索引擎 词位置加权_「seo基础」关键词推广:如何增加网站内容相关

    如何增加网站内容相关性,很多SEO常常会听到圈内人士大夫强调网站内容相关性.网站垂直等之类的言词,网站内容相关性高低也是决定关键词排名重要的环境因素之一,很多小鸟也问过大宝什么是网站内容相关性,如何提 ...

  5. python怎么用gamma函数_「gamma函数」Gamma函数 - seo实验室

    gamma函数 伽玛函数(Gamma函数),也叫欧拉第二积分,是阶乘函数在实数与复数上扩展的一类函数.该函数在分析学.概率论.偏微分方程和组合数学中有重要的应用.与之有密切联系的函数是贝塔函数,也叫第 ...

  6. Windows安装Apache注册服务出现(OS 5)拒绝访问。 : AH00369: Failed to open the Windows service manager,

    windows安装Apache,注册服务出现"(OS 5)拒绝访问. : AH00369: Failed to open the WinNT service manager..." ...

  7. cmd命令行窗口打开python文件显示拒绝访问

    刚开始学习python就遇到了各种问题 cmd命令行目录切换指令: 打开当前路径下的某一个文件夹:cd 文件名(cd小写,cd和文件名之间有一个空格) 返回上一级目录:cd.. 返回根目录:cd/ 用 ...

  8. 已使用管理员权限运行CMD,仍报错OSError: [WinError 5] 拒绝访问。: ‘E:\\Code\\Python\\Git\\stable-diffusion-webui\\venv\\

    已使用管理员权限运行CMD,仍报错OSError: [WinError 5] 拒绝访问.: 'E:\\Code\\Python\\Git\\stable-diffusion-webui\\venv\\ ...

  9. 配置安装Apache主服务发生错误:(OS 5)拒绝访问。 : AH00369: Failed to open the Windows service manager, perh······

    配置安装Apache主服务发生错误:(OS 5)拒绝访问.  : AH00369: Failed to open the Windows service manager, perhaps you fo ...

最新文章

  1. 黄仁勋入选《时代》杂志2021最具影响力100人,库克、马斯克也上榜
  2. WorkFlow For Net ! NET 平台工作流 或 BPM
  3. 根据16进制头文件识文件类型
  4. 《通过Web远程浏览并控制Tiny6410上的usb摄像头》---实战篇
  5. SAP CRM WebClient UI和Hybris backoffice UI开发的相同点
  6. node中的缓存机制
  7. ie 调用java的时候报错,调用javabean的非常郁闷的异常。
  8. 钉钉电脑版如何申请调休 钉钉电脑版申请调休方法
  9. c++_导入/导出excel文件
  10. C语言整数与字符串相互转换
  11. ic408服务器系统,威力铭408mt技术描述和配置.docx
  12. 【杂文】【python】Python 对象的析构
  13. git-osc自己定义控件之:CircleImageView
  14. 清除Mac OS X文件系统的附加属性@
  15. Android 7.0 Settings Summary 小记
  16. The client is closed
  17. matlab 插入标尺,Matlab如何设置自定义的画图标尺scale
  18. ​Au入门系列之三:调整音量
  19. RGW Bucket Shard优化
  20. 解决Windows提示缺少mfc140.dll文件的问题

热门文章

  1. java 读取栅格,提取两个重叠栅格的数据
  2. win8.1 windows无法在此计算机上设置家庭组,【求助】Windows无法从该家庭组中删除你的计算机...
  3. 直接将多个结果转化为数组
  4. Oracle 11g ADG 配置没问题,但死活不同步案例
  5. linux服务器系统内核参数优化
  6. CyclicBarrier底层实现和原理
  7. Apollo应用接入
  8. html中的空格表示
  9. long 和 Object的相互转换
  10. 深入浅出LVM on linux