python100例详解-几个小例子给你讲解Python中类的描述符
原标题:几个小例子给你讲解Python中类的描述符
学习 Python 这么久了,说起 Python 的优雅之处,能让我脱口而出的, Deor(描述符)特性可以排得上号。
描述符是Python 语言独有的特性,它不仅在应用层使用,在语言的基础设施中也有涉及。
我可以大胆地猜测,你对于描述符的了解是始于诸如 Django ORM 和 SQLAlchemy 中的字段对象,是的,它们都是描述符。你的它的认识,可能也止步于此,如果你没有去深究,它为何要如此设计?也就体会不到 Python 给我们带来的便利与优雅。
由于描述符的内容较多,长篇大论,容易让你倦怠,所以我打算分几篇来讲。
今天的话题是:为何要使用描述符?
假想你正在给学校写一个成绩管理系统,并没有太多编码经验的你,可能会这样子写。
classStudent:
def__init__(self, name, math, chinese, english):
self.name = name
self.math = math
self.chinese = chinese
self.english = english
def__repr__(self):
return"".format(
self.name, self.math, self.chinese, self.english
)
看起来一切都很合理
>>> std1 = Student( '小明', 76, 87, 68)
>>> std1
但是程序并不像人那么智能,不会自动根据使用场景判断数据的合法性,如果老师在录入成绩的时候,不小心录入了将成绩录成了负数,或者超过100,程序是无法感知的。
聪明的你,马上在代码中加入了判断逻辑。
classStudent:
def__init__(self, name, math, chinese, english):
self.name = name
if0<= math <= 100:
self.math = math
else:
raiseValueError( "Valid value must be in [0, 100]")
if0<= chinese <= 100:
self.chinese = chinese
else:
raiseValueError( "Valid value must be in [0, 100]")
if0<= chinese <= 100:
self.english = english
else:
raiseValueError( "Valid value must be in [0, 100]")
def__repr__(self):
return"".format(
self.name, self.math, self.chinese, self.english
)
这下程序稍微有点人工智能了,能够自己明辨是非了。
程序是智能了,但在__init__里有太多的判断逻辑,很影响代码的可读性。巧的是,你刚好学过 Property 特性,可以很好的应用在这里。于是你将代码修改成如下,代码的可读性瞬间提升了不少
classStudent:
def__init__(self, name, math, chinese, english):
self.name = name
self.math = math
self.chinese = chinese
self.english = english
@property
defmath(self):
returnself._math
@math.setter
defmath(self, value):
if0<= value <= 100:
self._math = value
else:
raiseValueError( "Valid value must be in [0, 100]")
@property
defchinese(self):
returnself._chinese
@chinese.setter
defchinese(self, value):
if0<= value <= 100:
self._chinese = value
else:
raiseValueError( "Valid value must be in [0, 100]")
@property
defenglish(self):
returnself._english
@english.setter
defenglish(self, value):
if0<= value <= 100:
self._english = value
else:
raiseValueError( "Valid value must be in [0, 100]")
def__repr__(self):
return"".format(
self.name, self.math, self.chinese, self.english
)
程序还是一样的人工智能,非常好。
你以为你写的代码,已经非常优秀,无懈可击了。
没想到,你的主管看了你的代码后,深深地叹了口气:类里的三个属性,math、chinese、english,都使用了 Property 对属性的合法性进行了有效控制。功能上,没有问题,但就是太啰嗦了,三个变量的合法性逻辑都是一样的,只要大于0,小于100 就可以,代码重复率太高了,这里三个成绩还好,但假设还有地理、生物、历史、化学等十几门的成绩呢,你得写多少行重复且没有意义的代码?我建议你去了解一下 Python 的描述符。
经过主管的指点,你知道了「描述符」这个东西。怀着一颗敬畏之心,你去搜索了下关于描述符的用法。
其实也很简单,一个实现了描述符协议的类就是一个描述符。
什么描述符协议?就是实现了__get__()、__set__()、__del__()其中至少一个方法的类,就是一个描述符。
__get__:用于访问属性。它返回属性的值,若属性不存在、不合法等都可以抛出对应的异常。
__set__:将在属性分配操作中调用。不会返回任何内容。
__delete__:控制删除操作。不会返回内容。
对描述符有了大概的了解后,你开始重写上面的代码。
如前所述,Score 类是一个描述器,当从 Student 的实例访问 math、chinese、english这三个属性的时候,都会经过 Score 类里的三个特殊的方法。这里的 Score 避免了 使用Property 出现大量的代码无法复用的尴尬。
classScore:
def__init__(self, default=0):
self._score = default
def__set__(self, instance, value):
ifnotisinstance(value, int):
raiseTypeError( 'Score must be integer')
ifnot0<= value <= 100:
raiseValueError( 'Valid value must be in [0, 100]')
self._score = value
def__get__(self, instance, owner):
returnself._score
def__del__(self):
delself._score
classStudent:
math = Score( 0)
chinese = Score( 0)
english = Score( 0)
def__init__(self, name, math, chinese, english):
self.name = name
self.math = math
self.chinese = chinese
self.english = english
def__repr__(self):
return"".format(
self.name, self.math, self.chinese, self.english
)
实现的效果和前面的一样,可以对数据的合法性进行有效控制(字段类型、数值区间等)
以上,我举了下具体的实例,从最原始的编码风格到 Property ,最后引出描述符。由浅入深,一步一步带你感受到描述符的优雅之处。
通过此文,你需要记住的只有一点,就是描述符给我们带来的编码上的便利,它在实现保护属性不受修改、属性类型检查的基本功能,同时有大大提高代码的复用率。返回搜狐,查看更多
责任编辑:
python100例详解-几个小例子给你讲解Python中类的描述符相关推荐
- python100例详解-Python编程之属性和方法实例详解
本文实例讲述了Python编程中属性和方法使用技巧.分享给大家供大家参考.具体分析如下: 一.属性 在python中,属性分为公有属性和私有属性,公有属性可以在类的外部调用,私有属性不能在类的外部调用 ...
- python100例详解-Python字典实现简单的三级菜单(实例讲解)
如下所示: data = { "北京":{ "昌平":{"沙河":["oldboy","test"] ...
- python100例详解-【学习笔记】python100例
1 #参考解法: 2 3 #!/usr/bin/python 4 #-*- coding: UTF-8 -*- 5 6 #year=int(input("年: ")) 7 #mon ...
- python100例详解-Python类和实例详解
可以看到,变量bart指向的就是一个Student的实例,后面的0x10a67a590是内存地址,每个object的地址都不一样,而Student本身则是一个类. 可以自由地给一个实例变量绑定属性,比 ...
- python100例详解-Python基础之列表常见操作经典实例详解
本文实例讲述了Python基础之列表常见操作.分享给大家供大家参考,具体如下: Python中的列表操作 列表是Python中使用最频繁的数据类型[可以说没有之一] 一组有序项目的集合 可变的数据类型 ...
- Python Unittest-根据不同测试环境跳过用例详解
Python Unittest-根据不同测试环境跳过用例详解 本文章会讲述以下几个内容: 1.Unittest 如何跳过用例 2.如何使用sys.argv 3.自动化测试项目中如何一套代码多套环境运行 ...
- 数据结构详解——最大(小)左倾树
数据结构详解--最大(小)左倾树 文章目录 数据结构详解--最大(小)左倾树 最大(小)左倾树的定义及用途 操作最大HBLT 合并操作 插入操作和删除操作 初始化操作 Java语言实现的最大HBLT ...
- STM32H750 更好用的CANFD 用例详解
目录 前言 Message RAM分配 STM32工程搭建 串口配置 100us定时器 FDCAN配置 Bus-Off处理 新消息接收处理 发送处理 使用Xavier配合测试一下 完整工程下载 关于用 ...
- 以SIGSEGV为例详解信号处理(与栈回溯)
以SIGSEGV为例详解信号处理(与栈回溯) 信号是内核提供的向用户态进程发送信息的机制, 常见的有使用SIGUSR1唤醒用户进程执行子程序或发生段错误时使用SIGSEGV保存用户错误现场. 本文以S ...
最新文章
- linux写文本命令,一天一个shell命令 linux文本操作系列-chmod命令用法
- 搜索引擎蜘蛛抓取主要依据用户的四种行为
- 数据中台实战(四):商品分析(产品设计篇)
- Spring Security + WebSocket——@MessageMapping中Authentication为NULL解决方案之一
- BZOJ1001 狼抓兔子 终于过了!
- MTK 2G芯片使用联通卡在深圳无法拨打112原因
- webstorm怎么跑项目_看不懂代码,不会用框架,新手程序员入职后如何快速上手项目?...
- 查看华为应用商店APPID
- Soft-Masked BERT 一种新的中文纠错模型
- nginx日志的监控【转】
- android studio mac svn插件,Mac下Android Studio升级SVN1.8(使用1.8format来checkout项目)
- jeb安装教程_JEB2插件教程之一
- uln2003驱动蜂鸣器_51单片机蜂鸣器
- 【雪碧图】url放置图片路径
- 高级OS(十五) - 中断机制以及中断上下部运行和内核代码分析
- 流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一)
- 微服务治理之分布式链路追踪--3.zipkin实战
- str开头的c语言函数介绍,C语言str函数系列
- python爬虫福利学习
- 如何提高高层住宅的消防安全性?安科瑞 许敏