当前位置: 首页 > 后端技术 > Python

【案例讲解】Python为什么要使用描述符?

时间:2023-03-25 20:52:23 Python

我用Python这么久了。说到Python的优雅,我可以脱口而出Descriptor(描述符)特性可以排在第一位。描述符是Python语言的一个独特特性。它们不仅用于应用层,还涉及语言基础设施。我可以大胆猜测,您对描述符的了解是从DjangoORM和SQLAlchemy中的字段对象开始的,是的,它们都是描述符。你对它的理解可能就到此为止了。如果你没有深入研究过,为什么会这样设计呢?也让我们不太了解Python给我们带来的便利和优雅。由于描述符的内容太长,很容易让大家看腻,所以打算分成几篇。今天的主题是:为什么要使用描述符?假设您正在为您的学校编写成绩管理系统。如果你没有太多的编码经验,你可能会这样写。classStudent:def__init__(self,name,math,chinese,english):self.name=nameself.math=mathself.chinese=chineseself.english=englishdef__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=nameif0<=math<=100:self.math=mathelse:raiseValueError("Validvaluemustbein[0,100]")if0<=chinese<=100:self.chinese=chineseelse:raiseValueError("Validvaluemustbein[0,100]")if0<=chinese<=100:self.english=englishelse:raiseValueError("Validvaluemustbein[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=nameself.math=mathself.chinese=chineseself.english=english@propertydefmath(self):returnself._math@math.setterdefmath(self,value):如果0<=value<=100:self._math=valueelse:raiseValueError("Valid值必须在[0,100]")@propertydefchinese(self):returnself._chinese@chinese.setterdefchinese(self,value):if0<=value<=100:self._chinese=valueelse:raiseValueError("Validvaluemustbein[0,100]")@propertydefenglish(self):returnself._english@english.setterdefenglish(self,value):if0<=value<=100:self._english=valueelse:raiseValueError("Validvaluemustbein[0,100]")def__repr__(self):return"".format(self.name,self.math,self.chinese,self.english)程序或同样的人工智能很好。你觉得你写的代码已经很好,无可挑剔了。没想到,人界之外也有那么一天。看完你的代码,小明深深的叹了口气:类中的三个属性,math,Chinese,English,都是用Property来有效的控制属性的合法性。从功能上来说,没有问题,就是太啰嗦了。三个变量的合法逻辑是一样的,只要大于0小于100即可。代码重复率太高了。这里的三个结果都不错,但是假设还是有地理、生物、历史、化学等几十个科目,这个代码简直受不了。让我们了解一下Python的描述符。经过小明的指点,你就知道“描述符”了。怀着敬畏之心,您搜索描述符的用法。其实也很简单。实现描述符协议的类是描述符。Whatdescriptorprotocol:一个类至少实现了__get__()、__set__()、__del__()中的一种方法就是描述符。__get__:用于访问属性。它返回属性的值。如果该属性不存在或不合法,则可以抛出相应的异常。__set__:将在属性赋值操作中被调用。不会返回任何东西。__delete__:控制删除操作。不会返回内容。对描述符有了大致的了解后,就开始重写上面的方法。如前所述,Score类是一个描述符。从Student实例访问math、Chinese、english三个属性时,会经过Score类中的三个特殊方法。这里的Score避免了使用Property大量代码无法复用的尴尬。类分数:def__init__(self,default=0):self._score=defaultdef__set__(self,instance,value):ifnotisinstance(value,int):raiseTypeError('Scoremustbeinteger')ifnot0<=value<=100:raiseValueError('有效值必须在[0,100]')self._score=valuedef__get__(self,instance,owner):returnself._scoredef__del__(self):delself._scoreclassStudent:math=Score(0)chinese=Score(0)english=Score(0)def__init__(self,name,math,chinese,english):self.name=nameself.math=mathself.chinese=chineseself.english=englishdef__repr__(self):return"".format(self.name,self.math,self.chinese,self.english)和上一个一样,可以有效控制数据的合法性(字段类型,取值区间等)上面我给出了具体的例子,从最原始的编码风格到Property,最后Extract描述符。由浅入深,一步步带你感受描述符的优雅。通过这篇文章,你唯一需要记住的就是描述符给我们带来的编码便利。实现了保护属性不被修改和检查属性类型的基本功能,同时大大提高了代码重用率。.