原标题:几个小例子给你讲解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中类的描述符相关推荐

  1. python100例详解-Python编程之属性和方法实例详解

    本文实例讲述了Python编程中属性和方法使用技巧.分享给大家供大家参考.具体分析如下: 一.属性 在python中,属性分为公有属性和私有属性,公有属性可以在类的外部调用,私有属性不能在类的外部调用 ...

  2. python100例详解-Python字典实现简单的三级菜单(实例讲解)

    如下所示: data = { "北京":{ "昌平":{"沙河":["oldboy","test"] ...

  3. python100例详解-【学习笔记】python100例

    1 #参考解法: 2 3 #!/usr/bin/python 4 #-*- coding: UTF-8 -*- 5 6 #year=int(input("年: ")) 7 #mon ...

  4. python100例详解-Python类和实例详解

    可以看到,变量bart指向的就是一个Student的实例,后面的0x10a67a590是内存地址,每个object的地址都不一样,而Student本身则是一个类. 可以自由地给一个实例变量绑定属性,比 ...

  5. python100例详解-Python基础之列表常见操作经典实例详解

    本文实例讲述了Python基础之列表常见操作.分享给大家供大家参考,具体如下: Python中的列表操作 列表是Python中使用最频繁的数据类型[可以说没有之一] 一组有序项目的集合 可变的数据类型 ...

  6. Python Unittest-根据不同测试环境跳过用例详解

    Python Unittest-根据不同测试环境跳过用例详解 本文章会讲述以下几个内容: 1.Unittest 如何跳过用例 2.如何使用sys.argv 3.自动化测试项目中如何一套代码多套环境运行 ...

  7. 数据结构详解——最大(小)左倾树

    数据结构详解--最大(小)左倾树 文章目录 数据结构详解--最大(小)左倾树 最大(小)左倾树的定义及用途 操作最大HBLT 合并操作 插入操作和删除操作 初始化操作 Java语言实现的最大HBLT ...

  8. STM32H750 更好用的CANFD 用例详解

    目录 前言 Message RAM分配 STM32工程搭建 串口配置 100us定时器 FDCAN配置 Bus-Off处理 新消息接收处理 发送处理 使用Xavier配合测试一下 完整工程下载 关于用 ...

  9. 以SIGSEGV为例详解信号处理(与栈回溯)

    以SIGSEGV为例详解信号处理(与栈回溯) 信号是内核提供的向用户态进程发送信息的机制, 常见的有使用SIGUSR1唤醒用户进程执行子程序或发生段错误时使用SIGSEGV保存用户错误现场. 本文以S ...

最新文章

  1. linux写文本命令,一天一个shell命令 linux文本操作系列-chmod命令用法
  2. 搜索引擎蜘蛛抓取主要依据用户的四种行为
  3. 数据中台实战(四):商品分析(产品设计篇)
  4. Spring Security + WebSocket——@MessageMapping中Authentication为NULL解决方案之一
  5. BZOJ1001 狼抓兔子 终于过了!
  6. MTK 2G芯片使用联通卡在深圳无法拨打112原因
  7. webstorm怎么跑项目_看不懂代码,不会用框架,新手程序员入职后如何快速上手项目?...
  8. 查看华为应用商店APPID
  9. Soft-Masked BERT 一种新的中文纠错模型
  10. nginx日志的监控【转】
  11. android studio mac svn插件,Mac下Android Studio升级SVN1.8(使用1.8format来checkout项目)
  12. jeb安装教程_JEB2插件教程之一
  13. uln2003驱动蜂鸣器_51单片机蜂鸣器
  14. 【雪碧图】url放置图片路径
  15. 高级OS(十五) - 中断机制以及中断上下部运行和内核代码分析
  16. 流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一)
  17. 微服务治理之分布式链路追踪--3.zipkin实战
  18. str开头的c语言函数介绍,C语言str函数系列
  19. python爬虫福利学习
  20. 如何提高高层住宅的消防安全性?安科瑞 许敏

热门文章

  1. CUDA 多GPU调用实现
  2. OpenGL ES基本用法
  3. interpolation algorithm
  4. RabbitMQ connection.CreateModel() 分析
  5. TCP/IP 基础简介
  6. javaweb——总结
  7. nginx + tomcat + redis 部署项目,解决session共享问题。
  8. 安全漏洞整改解决方案
  9. UVA11777 Automate the Grades【水题】
  10. UVA10074 Take the Land【最大子段和+DP】