Python 代理类实现和控制访问与修改属性的权限

本篇文章主要内容

代理类主要功能是将一个类实例的属性访问和控制代理到代码内部另外一个实例类,将想对外公布的属性的访问和控制权交给代理类来操作,保留不想对外公布的属性的访问或控制权,比如只读访问,日志功能

  1. 在代理类中实现被代理的类属性访问和修改权限控制
  2. 异常捕获代理类的简化示例

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

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

# proxy_example1.py
# 以下是一个代理类实现只读访问的示例
# 目标:代理后只能访问和修改Product的公开属性,私有属性_current只能查看不能修改
class Product:def __init__(self, price, quantity):self.price = priceself.quantity = quantityself._current = 123# 只暴露代理类Proxy给外部使用
class Proxy:def __init__(self, obj):self._obj = objdef __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 = 1print(pp.abc, p.abc)pp._curr = 10000print(pp._curr)  # 私有属性,设置给了代理类print(p._curr)  # raise an error, 被代理的类Product的属性没有设置成功也无法访问def test_delattr():p = Product(10, 2)pp = Proxy(p)pp.abc = 123print(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_setattr()

输出

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.py
class Product:def __init__(self, price, quantity):self.price = priceself.quantity = quantityself._current = 123def __len__(self):return 111# 只暴露代理类Proxy给外部使用
class Proxy:def __init__(self, obj):self._obj = objdef __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)@propertydef __class__(self):    # 伪造__class__属性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__,会返回Falsedef 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()

输出

<class '__main__.Product'>
True

测试获取长度

if __name__ == '__main__':test_len()

输出

111

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

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

# logger_proxy.py
# -*- coding:utf-8 -*-
from functools import wrapsclass DAL:@classmethoddef dm1(cls, req, *args):print("dm1...", f"{req=}")print(1/0)      # 故意抛出异常return "dm1"class BLL:@classmethoddef bm1(cls, req):print("bm1...", f"{req=}")return DAL.dm1(req)class Application:def __init__(self, req):self.req = reqself._p = "private attr"def hd1(self):return BLL.bm1(self.req)class LoggerProxy:def __init__(self, obj):self._obj = objdef __getattr__(self, item):    # LoggerProxy类实例没获取到的属性会执行这个方法attr = getattr(self._obj, item)if callable(attr):  # 获取到了方法,则处理异常捕获@wraps(attr)def wrapped_method(*args, **kwargs):# print(f"Before accessing 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 methodreturn wrapped_methodelse:   # 获取到了属性,直接返回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双下划线开头和结尾的方法,如果想要被代理类访问和控制就必须在代理类中也定义对应的实际方法,另外,示例中主要是以下划线开头的方法作为私有属性的约定,也可以使用其他约定,这样在代理方法中的访问和修改时做出相应的判断即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php 对象赋值后改变成员变量影响赋值对象

话不多说看代码 <?php class obj {}$obj1new obj();//实例化对象 $obj2$obj1;//赋值新对象 $obj1->name"test";//改变老对象的成员变量属性 var_dump($obj1); var_dump($obj2); $obj2->name"name";//改变新对象的成员变量属性 var_dump($obj1); …

Android Camera 通过V4L2与kernel driver的完整交互过程

原文地址&#xff1a;Android Camera 通过V4L2与kernel driver的完整交互过程 作者&#xff1a;xinyuwuxian Android Camera 通过V4L2与kernel driver的完整交互过程之前在 Android Camera 的执行流程http://blog.chinaunix.net/uid-26765074-id-3499537.html这篇文章中已经详细…

【Pytorch神经网络理论篇】 05 Module类的使用方法+参数Parameters类+定义训练模型的步骤与方法

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

Python实现访问者模式

假设要实现一个存放多种类型数据结构的对象&#xff0c;比如一个存放算术操作数和操作符的树结点&#xff0c;需要存放包含一元操作符、二元操作符和数字类型的结点 class Node:passclass UnaryOperator(Node):def __init__(self, operand):self.operand operandclass Binary…

BZOJ 2822: [AHOI2012]树屋阶梯 [Catalan数 高精度]

2822: [AHOI2012]树屋阶梯 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 779 Solved: 453[Submit][Status][Discuss]Description 暑假期间&#xff0c;小龙报名了一个模拟野外生存作战训练班来锻炼体魄&#xff0c;训练的第一个晚上&#xff0c;教官就给他们出了个难题。由…

Python缓存类实例

本篇文章的内容主要包含 利用Python弱引用存储字典缓存类的实例&#xff0c;让参数相同的实例不用重复生成略过复杂的通用化代码编写&#xff0c;利用Python自带库来缓存实例和方法对象 在Python的许多库中都有缓存实例的例子&#xff0c;比如logging模块的Logger类实例 imp…

【Pytorch神经网络理论篇】 06 神经元+神经网络模型+全连接网络模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

面试题:N皇后问题,思路和python解题笔记

n皇后问题算法思路和python解法 问题描述 n皇后问题&#xff0c;在nn的棋盘上&#xff0c;解出n个皇后所有不能互相攻击的摆法&#xff0c; 皇后在数组中用“Q”表示&#xff0c;空地用“.”表示 返回的数据结构格式要求&#xff1a;[[“.Q…”,“…Q”,“Q…”,“…Q.”],[“…

【Pytorch神经网络理论篇】 07 激活函数+Sigmoid+tanh+ReLU+Swish+Mish+GELU

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

截图命令

adb shell /system/bin/screencap -p /sdcard/screenshot.png adb pull /sdcard/screenshot.png E:\

【Pytorch神经网络理论篇】 08 Softmax函数(处理分类问题)

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

Python套接字编程Socket Progaming——1

本篇文章是Network And Web Programing-Socket Programing分类中的第一篇文章&#xff0c;内容主要包含 Socket概念理解Socket programing介绍一个简单的TCP协议的server-client程序支持同时处理多个客户端简单server-client连接程序socket的常用选项使用 理解socket概念 一…

【Pytorch神经网络理论篇】 09 神经网络模块中的损失函数

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

jquery hover事件中 fadeIn和fadeOut 效果不能及时停止

$(".nav ul li").hover(function () {var id $(this).attr("id");$(".nav dl").each(function (index, domEle) {if ($(domEle).attr("id") id) {$(domEle).fadeIn();}else {$(domEle).stop().fadeOut();//在这里加入.stop() 以阻止…

【Pytorch神经网络理论篇】 10 优化器模块+退化学习率

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

Android fb0 截屏实现

问题:我们有几个项目,在项目1和项目2上实现截屏是没有问题的,但是在项目3上实现截屏是不行的 原因:分辨率差异引起的问题,分辨率长宽一定要是32的整数倍 Dear customer, Sorry for the late reply due to annual leave. I dont think this issue relates with thediff…

Python trino执行hive insert overwrite不生效的问题

使用python的trino包执行insert overwrite&#xff0c;但是overwrite却没有生效的问题 根据trino的官网介绍的insert overwrite的开启方式&#xff0c;开启hive的insert overwrite会话&#xff0c;使当前会话的insert into语句支持insert overwrite&#xff0c;也即支持插入数…

HAProxy负载均衡原理及企业级实例部署haproxy集群

HAProxy是一种高效、可靠、免费的高可用及负载均衡解决方案&#xff0c;非常适合于高负载站点的七层数据请求。客户端通过HAProxy代理服务器获得站点页面&#xff0c;而代理服务器收到客户请求后根据负载均衡的规则将请求数据转发给后端真实服务器。 同一客户端访问服务器&…

【Pytorch神经网络实战案例】07 预测泰坦尼克号上生存的乘客

1 样本处理 1.1 载入样本代码---Titanic forecast.py&#xff08;第1部分&#xff09; import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from scipy import stats import pandas as pd import matplotlib.pyplot as plt import os o…

ubuntu下 安装 adb

1、把adb tool工具考到你要安装的目录夏目 <