我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python 实现 代理模式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python 实现 代理模式

本文的目录地址

本文的代码地址

在某些应用中,我们需要在访问某个对象之前执行一个或多个重要的操作,例如,访问敏感信息——在允许用户访问敏感信息之前,我们希望确保用户具备足够的权限。操作系统也存在类似的情况,用户必须具有管理员权限才能在系统中安装新程序。

上面提到的重要操作不一定与安全问题相关。延迟初始化是另一个案例:我们想要把一个计算成本较高的对象的创建过程延迟到用户首次真正使用它时才进行。

这类操作通常使用代理设计模式(Proxy design pattern)来实现。该模式因使用代理(又名替代,surrogate)对象在访问实际对象之前执行重要操作而得其名。以下是四种不同的知名代理类型。

  • 远程代理:实际存在于不同地址空间(例如,某个网络服务器)的对象在本地的代理者。
  • 虚拟代理:用于懒初始化,将一个大计算量对象的创建延迟到真正需要的时候进行。
  • 保护/防护代理:控制对敏感对象的访问。
  • 智能(引用)代理:在对象被访问时执行额外的动作。此类代理的例子包括引用计数和线程安全检查。

应用案例

因为存在至少四种常见的代理类型,所以代理设计模式有很多应用案例,如下所示.

  • 在使用私有网络或云搭建一个分布式系统时。在分布式系统中,一些对象存在于本地内存中,一些对象存在于远程计算机的内存中。如果我们不想本地代码关心两者之间的区别,那么刻意创建一个远程代理来隐藏/封装,使得应用的分布式性质透明化。
  • 因过早创建计算陈本较高的对象导致应用遭受性能问题之时。使用虚拟代理引入懒初始化,仅在真正需要对象之时才创建,能够明显提高性能。
  • 用于检查一个用户是否有足够权限来访问某个信息片段。如果应用要处理敏感信息(例如,医疗数据),我们会希望确保用户在被准许之后才能访问/修改数据。一个保护/防护代理可以处理所有安全相关的行为。
  • 应用(或库、工具集、框架等)使用多线程,而我们希望把线程安全的重任从客户端代码转移到应用。这种情况下,可以创建一个智能代理,对客户端隐藏线程安全的复杂性。
  • 对象关系映射(Object-Relational Mapping,ORM)API也是一个如何使用远程代理的例子。包括Django在内的许多流行Web框架使用一个ORM来提供类OOP的关系型数据库访问。ORM是关系型数据库的代理,数据库可以部署在任意地方,本地或远程服务器都可以。

实现一

我发现虚拟代理非常有用,所以现在通过一个例子来看看可以如何实现它。

使用Python来创建虚拟代理存在很多方式,但我始终喜欢地道的符合Python风格的实现。这里展示的代码源自网站stackoverflow.com用户Cyclone的一个超赞回答。我们先创建一个LazyProperty类,用作一个修饰器。当它修饰某个特性时,LazyProperty惰性地(首次使用时)加载特性,而不是立即进行。__init__方法创建两个变量,用作初始化待修饰特性的方法的别名。method变量是一个实际方法的别名,method_name变量则是该方法名称的别名。

class LazyProperty:
    def __init__(self,method):
        self.method=method
        self.method_name=method.__name__   
        

LazyProperty类实际上是一个描述符.描述符(descriptor)是Python中重写类属性访问方法(__get__()、__set__()和__delete__())的默认行为要使用的一种推荐机制。LazyProperty类仅重写了__get__(),因为这是其需要重写的唯一访问方法。换句话说,我们无需重写所有访问方法。__get__()方法所访问的特性值,正是下层方法想要赋的值,并使用setattr()来手动赋值。__get__()实际做的事情非常简单,就是使用值来替代方法!这意味着不仅特性是惰性加载的,而且仅可以设置一次。我们马上就能看到这意味着什么。取消注释,可以得到一些额外信息。

def __get__(self, instance, owner):
        if not instance:
            return  None
        value=self.method(instance)
        #print(('value {}'.format(value)))
        setattr(instance,self.method_name,value)
        return value

Test类演示了我们可以如何使用LazyProperty类。其中有三个属性,x、y和_resoure。我们想懒加载_resource变量,因此将其初始化为None,resource()方法是使用LazyProperty类修饰的。因演示目的,LazyProperty类将_resource属性初始化为一个tuple,通常来说这是一个缓慢/代价大的初始化过程(初始化数据库、图形等)。

class Test:
    def __init__(self):
        self.x='foo'
        self.y='bar'
        self._resouce=None

    @LazyProperty
    def resource(self):
        print('initializing self._resource which is: {}'.format(self._resouce))
        self._resouce=tuple(range(5))  # 代价大的
        return self._resouce

main()函数展示了懒初始化是如何进行的。注意,__get__()访问方法的重写使得可以将resouce()方法当做一个变量(可以使用t.resource代替t.resource())。

def main():
    t=Test()
    print(t.x)
    print(t.y)
    # 做更多的事情。。。
    print(t.resource)
    print(t.resource)

运行结果:

foo
bar
initializing self._resource which is: None
(0, 1, 2, 3, 4)
(0, 1, 2, 3, 4)

从这个例子(文件lazy.py)的执行输出中,可以看出:

  • _resource变量实际不是在t实例创建时初始化的,而是在我们首次使用t.resource时。
  • 第二次使用t.resource时,并没有再次初始化变量。这就是为什么初始化字符串initializing self._resource which is仅出现一次的原因。

在OOP中有两种基本的、不同类型的懒初始化,如下:

  • 在实例级:这意味着会对一个对象的特性进行懒初始化,但该特性有一个对象作用域。同一个类的每个实例(对象)都有自己的(不同的)特性副本。
  • 在类级或模块级:在这种情况下,我们不希望每个实例都有一个不同的特性副本,而是所有实例共享同一个特性,而特性是懒初始化的。这里没有给出示例,你可以将其作为练习。

实现二

我们将实现一个简单的保护代理来查看和添加用户。该服务提供两个选项:

查看用户列表:这一操作不需要特殊权限

添加新用户:这一操作要求客户端提供一个特殊的密码。

SensitiveInfo类包含我们希望保护的信息。users变量是已有用户的列表。read()方法输出用户列表。add()方法将一个新用户添加到列表中。

class SensitiveInfo:
    def __init__(self):
        self.users = ['nick', 'tom', 'ben', 'mike']

    def read(self):
        print("There are {} users: {}".format(len(self.users), ' '.join(self.users)))

    def add(self, user):
        self.users.append(user)
        print("Added user {}".format(user))

Info类是SensitiveInfo的一个保护代理。secret变量值是客户端代码在添加新用户时被要求告知/提供的密码。注意,这只是一个例子。现实中,永远不要执行以下操作。

  • 在源代码中存储密码
  • 以明文形式存储密码
  • 使用一种弱(例如,MD5)或自定义加密形式

read()方法是SensitiveInfo.read()的一个包装。add()方法确保仅当客户端代码知道密码时才能添加新用户。

class Info:
    def __init__(self):
        self.protected=SensitiveInfo()
        self.secret='0xdeadbeef'
        
    def read(self):
        self.protected.read()
        
    def add(self,user):
        sec=input('What is the secret?')
        self.protected.add(user) if sec==self.secret else print("That's wrong!")
        

main()函数展示了客户端代码可以如何使用代理模式。客户端代码创建一个Info类的实例,并使用菜单让用户选择来读取列表、添加新用户或退出应用。

def main():
    info = Info()
    while True:
        print('1. read list |==| 2. add user |==| 3. quit')
        key = input('choose option: ')
        if key == '1':
            info.read()
        elif key == '2':
            name = input('choose username: ')
            info.add(name)
        elif key == '3':
            exit()
        else:
            print('unknown option: {}'.format(key))

点击获取完整代码proxy.py

运行结果:

/usr/bin/python3.6 /home/pig/PycharmProjects/wd/proxyPattern_09/proxy.py
1. read list |==| 2. add user |==| 3. quit
choose option: 1
There are 4 users: nick tom ben mike
1. read list |==| 2. add user |==| 3. quit
choose option: 2
choose username:333
What is the secret?0xdeadbeef
Added user 333
1. read list |==| 2. add user |==| 3. quit
choose option: 1
There are 5 users: nick tom ben mike 333
1. read list |==| 2. add user |==| 3. quit
choose option: ss
unknown option: ss
1. read list |==| 2. add user |==| 3. quit
choose option: 3


Process finished with exit code 0

Q1:该示例有一个安全缺陷。即可以直接创建SensitiveInfo实例来绕过安全设置。如何优化实例来阻止这种情况。一种方式是使用abc模块来禁止直接实例化SensitiveInfo。动手试试吧。

proxy_q1.py

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python 实现 代理模式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python 实现 代理模式

本文的目录地址本文的代码地址在某些应用中,我们需要在访问某个对象之前执行一个或多个重要的操作,例如,访问敏感信息——在允许用户访问敏感信息之前,我们希望确保用户具备足够的权限。操作系统也存在类似的情况,用户必须具有管理员权限才能在系统中安装
2023-01-31

Java代理模式如何实现

这篇文章主要介绍“Java代理模式如何实现”,在日常操作中,相信很多人在Java代理模式如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java代理模式如何实现”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-19

Go代理模式怎么实现

Go语言中实现代理模式可以使用结构体和接口的方式。首先,定义一个接口,代理和被代理对象都必须实现这个接口。这里以一个简单的计算器为例:```gotype Calculator interface {Add(a, b int) intSubt
2023-08-08

java如何实现代理模式

小编给大家分享一下java如何实现代理模式,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象
2023-05-30

Java代理模式怎么实现

这篇文章主要讲解了“Java代理模式怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java代理模式怎么实现”吧!结构型模式前面创建型模式介绍了创建对象的一些设计模式,这节介绍的结构型
2023-06-02

Java设计模式之代理模式原理及实现代码分享

简介Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术。生活中的方方面面都可以虚拟到代码中。代理模式所讲的就是现实生活中的这么一个概念:中介。代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
2023-05-30

Java设计模式的代理模式怎么实现

这篇文章主要介绍了Java设计模式的代理模式怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java设计模式的代理模式怎么实现文章都会有所收获,下面我们一起来看看吧。什么是代理模式代理模式的定义: 由于某
2023-06-30

Java中如何实现代理模式

这期内容当中小编将会给大家带来有关Java中如何实现代理模式,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。简介摘要: 代理模式是GOF设计模式中的一种,常用于权限模块的架构设计,其根本的原理是通过将一个代
2023-06-17

Java结构型模式之代理模式怎么实现

今天小编给大家分享一下Java结构型模式之代理模式怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一.介绍在代理模式(
2023-07-05

PHP结构型模式之代理模式怎么实现

这篇文章主要讲解了“PHP结构型模式之代理模式怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP结构型模式之代理模式怎么实现”吧!代理模式的优点代理模式可以保护原对象,控制对原对象
2023-07-05

Java动态代理模式怎么实现

这篇文章主要介绍“Java动态代理模式怎么实现”,在日常操作中,相信很多人在Java动态代理模式怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java动态代理模式怎么实现”的疑惑有所帮助!接下来,请跟
2023-06-17

如何在Java中实现代理模式

这篇文章将为大家详细讲解有关如何在Java中实现代理模式,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程序;
2023-06-15

SpringAop实现原理及代理模式是什么

这篇文章主要介绍了SpringAop实现原理及代理模式是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringAop实现原理及代理模式是什么文章都会有所收获,下面我们一起来看看吧。Spring Aop的
2023-06-29

Python实现享元模式的示例代码

本文详细讲解了Python中实现享元模式的示例代码,介绍了享元模式的原理和优势。通过工厂模式管理享元对象,代码示例展示了如何在Python中使用享元对象共享共同状态,从而减少内存消耗和提高性能。享元对象的固有状态不可变,外部状态由客户端对象处理,优点包括降低内存占用、提升性能和增强代码可维护性。
Python实现享元模式的示例代码
2024-04-02

.Net结构型设计模式之代理模式怎么实现

这篇文章主要介绍了.Net结构型设计模式之代理模式怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇.Net结构型设计模式之代理模式怎么实现文章都会有所收获,下面我们一起来看看吧。一、动机(Motivate
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录