千家信息网

Python的代理类怎么实现

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇"Python的代理类怎么实现"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Py
千家信息网最后更新 2025年01月19日Python的代理类怎么实现

这篇"Python的代理类怎么实现"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Python的代理类怎么实现"文章吧。

代理类的一个简单的实现方式示例

目标:实现类Product的实例属性让另一个类Proxy来代理访问和控制,想将对外公布的属性交给代理类让外部访问和控制,不想对外公布的属性无法通过代理来访问和控制,这里不想对外公布的属性约定用下划线命名开头

# proxy_example1.py# 以下是一个代理类实现只读访问的示例# 目标:代理后只能访问和修改Product的公开属性,私有属性_current只能查看不能修改class Product:    def __init__(self, price, quantity):        self.price = price        self.quantity = quantity        self._current = 123# 只暴露代理类Proxy给外部使用class Proxy:    def __init__(self, obj):        self._obj = obj    def __getattr__(self, item):    # 本实例没有找到的属性会执行__getattr__方法        if item.startswith("_"):    # 约定下划线开头的方法不能访问到被代理的类,只会访问到代理类            raise Exception(f"{item} not found")    # Product存在的私有属性也不希望被外部知道        return getattr(self._obj, item)    def __setattr__(self, key, value):        if key.startswith("_"):     # 约定下划线开头的方法不能访问到被代理的类,只会访问到代理类            # 注:这里不能raise,这会导致Proxy的实例都无法创建(__dict__等属性无法创建)            super(Proxy, self).__setattr__(key, value)   # 避免无限循环        else:            setattr(self._obj, key, value)    # 要求只能删除非下划线开头的属性    def __delattr__(self, item):        if item.startswith("_"):            super(Proxy, self).__delattr__(item)    # 避免无限循环        else:            delattr(self._obj, item)def test_getattr():    p = Product(10, 1)    pp = Proxy(p)    print(pp.price)    print(pp._curr)def test_setattr():    p = Product(10, 2)    pp = Proxy(p)    pp.abc = 1    print(pp.abc, p.abc)    pp._curr = 10000    print(pp._curr)  # 私有属性,设置给了代理类    print(p._curr)  # raise an error, 被代理的类Product的属性没有设置成功也无法访问def test_delattr():    p = Product(10, 2)    pp = Proxy(p)    pp.abc = 123    print(pp.abc, p.abc)    # 删除公开属性    del pp.abc  # 成功    # print(pp.abc, p.abc)  # 已被删除    # # 删除私有属性    # del pp._curr    # 会尝试删除Proxy的私有属性,raise AttributeError: _curr    # 先创建在删除    pp._def = 123   # 这个操作只会设置Proxy的实例属性    print(pp._def)      # 访问的是Proxy实例属性,被代理的Product实例没有创建_def属性    # del pp._def     # 删除的是Proxy的实例属性    # print(pp._def)

测试获取属性

if __name__ == '__main__':    test_getattr()

输出:

10
...
Exception: _curr not found
...

测试设置属性

if __name__ == '__main__':    test_delattr()

输出

1 1
10000
...
AttributeError: 'Product' object has no attribute '_curr'
...

测试删除属性

if __name__ == '__main__':    test_delattr()

输出

123 123
123

注:以双下划线开头和结尾的方法无法被代理,想要使用,必须在代理类中定义出这个方法,然后重定向到被代理的类的方法,比如你想使用isinstance()方法就要在Proxy伪造定义__class__属性,想要使用len()方法就要在Proxy重定向返回到被代理的类的len方法

# proxy_example2.pyclass Product:    def __init__(self, price, quantity):        self.price = price        self.quantity = quantity        self._current = 123    def __len__(self):        return 111# 只暴露代理类Proxy给外部使用class Proxy:    def __init__(self, obj):        self._obj = obj    def __getattr__(self, item):    # 本实例没有找到的属性会执行__getattr__方法        if item.startswith("_"):    # 约定下划线开头的方法不能访问到被代理的类,只会访问到代理类            raise Exception(f"{item} not found")    # Product存在的私有属性也不希望被外部知道        return getattr(self._obj, item)    def __setattr__(self, key, value):        if key.startswith("_"):     # 约定下划线开头的方法不能访问到被代理的类,只会访问到代理类            # 注:这里不能raise,这会导致Proxy的实例都无法创建(__dict__等属性无法创建)            super(Proxy, self).__setattr__(key, value)   # 避免无限循环        else:            setattr(self._obj, key, value)    # 要求只能删除非下划线开头的属性    def __delattr__(self, item):        if item.startswith("_"):            super(Proxy, self).__delattr__(item)    # 避免无限循环        else:            delattr(self._obj, item)    @property    def __class__(self):    # 伪造类        return self._obj.__class__    def __len__(self):        return len(self._obj)        def test_instance():            p = Product(10, 2)            pp = Proxy(p)            print(pp.__class__)            print(isinstance(pp, Product))      # 如果不伪造__class__,会返回False        def test_len():            p = Product(10, 2)            pp = Proxy(p)            print(len(pp))  # 如果Proxy实例不定义__len__方法,会报错TypeError: object of type 'Proxy' has no len()

测试伪造的实例class类型

if __name__ == '__main__':    test_instance()

输出


True

测试获取长度

if __name__ == '__main__':    test_len()

输出

111

一个实现日志输出的代理类的简化示例

捕获web server报错日志并执行异常处理的示例

# logger_proxy.py# -*- coding:utf-8 -*-from functools import wrapsclass DAL:    @classmethod    def dm1(cls, req, *args):        print("dm1...", f"{req=}")        print(1/0)      # 故意抛出异常        return "dm1"class BLL:    @classmethod    def bm1(cls, req):        print("bm1...", f"{req=}")        return DAL.dm1(req)class Application:    def __init__(self, req):        self.req = req        self._p = "private attr"    def hd1(self):        return BLL.bm1(self.req)class LoggerProxy:    def __init__(self, obj):        self._obj = obj    def __getattr__(self, item):    # LoggerProxy类实例没获取到的属性会执行这个方法        attr = getattr(self._obj, item)        if callable(attr):  # 获取到了方法,则处理异常捕获            @wraps(attr)            def wrapped_method(*args, **kwargs):                # print(f"Before access to attribute/method: {item}")                try:                    method = attr(*args, **kwargs)                except ZeroDivisionError:                    # 捕获异常然后处理...                    raise Exception(f"{attr.__name__} received a zero division error.")                # print(f"After attribute/method {item} returned")                return method            return wrapped_method        else:   # 获取到了属性,直接返回            return attrif __name__ == '__main__':    lp = LoggerProxy(Application("abc"))    print(lp.req)    print(lp._p)    print(lp.hd1())

运行输出

abc
private attr
bm1... req='abc'
dm1... req='abc'
Traceback...
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback...
Exception: hd1 received a zero division error.

以上就是关于"Python的代理类怎么实现"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

属性 代理 方法 实例 开头 输出 下划线 私有 内容 测试 约定 示例 循环 处理 控制 成功 文章 日志 目标 知识 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 命运2连接不上服务器 宿州网络安全宣传周启动直播 校园网络安全督查通知 计算机系统网络安全工程 药品销售数据库毕业论文 2010数据分组显示数据库 服务器怎么格式化数据盘 网络安全方面的开设院校 360奇酷互联网科技公司 用水管理软件开发建议书 南京海航软件开发销售电话 学习网络安全法活动结束语 济南招聘网络安全工程师 wincc怎么在服务器读数据 v10服务器是哪个国家的 数据库一体机的市场规模 服务器硬盘容量怎么看 数据库改到本机 有单方块生存的服务器 网络技术优化的目的是 激活畅连时服务器异常 怎样选云服务器售价 网页游戏某些服务器登不上去 金蝶破解数据库激活命令 潍坊鑫晟网络技术有限公司 网络安全大赛国网 计算机网络技术第八版答案第四章 河北it软件开发销售价格 软件开发外包保密协议豆丁网 数据库删除用户帐号命令
0