Python 属性装饰器 @property 基础用法
文章目录前言我被一个假属性坑了整整三天一、property 到底是啥说白了就是个整容医生二、传统写法的痛懂的都懂三、property 登场一行代码拯救强迫症四、实战案例电商系统的价格保卫战五、只读属性让某些数据只准看不准摸六、property 的隐藏技能计算属性七、踩坑指南这些坑我帮你踩过了八、结语property 真香P.S. 目前国内还是很缺AI人才的希望更多人能真正加入到AI行业共同促进行业进步增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow教程通俗易懂高中生都能看懂还有各种段子风趣幽默从深度学习基础原理到各领域实战应用都有讲解我22年的AI积累全在里面了。注意教程仅限真正想入门AI的朋友否则看看零散的博文就够了。前言我被一个假属性坑了整整三天说实话刚开始学Python那会儿我一度以为自己掌握了面向对象的精髓。不就是class嘛不就是self嘛直到重构一个电商后台系统我差点被一个小小的属性访问问题整破防了……事情是这样的。我写了个Product类里面有个price字段。起初简单粗暴直接self.price price完事儿。结果产品经理突然说“价格不能为负数啊要是程序里把价格算成了-50块数据库一写进去财务那边直接炸裂”行吧那我加个校验呗。把price改成私有属性_price然后写两个方法get_price()和set_price()。改完一运行我蚌埠住了——调用方代码全崩了几百个地方都在用product.price 19.9这种写法现在全得改成product.set_price(19.9)。这工作量……我当场就想提桶跑路。就在这时候一个后端大佬默默发给我一行代码property。我试了下卧槽代码不用改功能还能加这就是Python最骚的操作之一今天必须给你们整明白一、property 到底是啥说白了就是个整容医生要搞懂property咱得先聊聊别的语言是怎么做的。Java和C那帮老派程序员特别喜欢getter/setter模式。啥意思呢就是不管啥属性先藏起来private然后通过两个方法去操作。取数据用get_xxx()存数据用set_xxx()。美其名曰封装实际上……代码写得像八股文又臭又长。Python就不一样了。Python的设计哲学是简单优于复杂但也得考虑扩展性啊于是property应运而生。它本质上是个装饰器能把一个方法伪装成属性。你访问的时候像变量实际上背后跑的是方法。这就叫表里不一但深得我心举个例子你就懂了。就像你去住酒店门卡刷一下门开了。对你来说就是插卡开门这么个简单动作。但背后呢酒店系统要验证房号、检查有效期、记录开门时间、甚至可能还要联动电梯权限。property就是帮你把这些复杂逻辑藏到插卡这个动作背后对外看起来还是那么简单。二、传统写法的痛懂的都懂在property出现之前咱们怎么处理属性校验的来看段考古代码classCircle:definit(self,radius):self._radiusradius# 下划线开头假装私有defget_radius(self):returnself._radiusdefset_radius(self,value):ifvalue0:raiseValueError(半径不能为负数啊喂)self._radiusvalue用起来是这样的cCircle(5)print(c.get_radius())# 输出5c.set_radius(10)# 正常修改c.set_radius(-5)# 报错发现问题没丑太丑了 每次访问属性都得带括号像便秘一样不畅快。更可怕的是如果你一开始直接用了c.radius 5这种简单写法后来想加校验就得把所有调用方代码都改一遍。这在大型项目里简直是噩梦几百个文件等着你翻修……我当时就卡在这种情况。代码已经写了3万多行突然要改接口风格项目经理的眼神能杀人。说实话那段时间我晚上做梦都在改get_xxx()和set_xxx()睡醒枕头都是湿的。三、property 登场一行代码拯救强迫症property的写法看完之后我直接献上膝盖classCircle:definit(self,radius):self._radiusradiuspropertydefradius(self):returnself._radiusradius.setterdefradius(self,value):ifvalue0:raiseValueError(半径不能为负数想啥呢)self._radiusvalue用起来……丝滑cCircle(5)print(c.radius)# 看起来是访问属性实际是调getterc.radius10# 看起来是赋值实际是调setterc.radius-5# 照样报错但写法完全没变看到没调用方式完全没变 对用户来说c.radius还是c.radius但背后已经加了层层校验。这就是property的精髓——后期加逻辑不改前期代码。这种向后兼容的能力在2025年的敏捷开发里简直是刚需需求天天变代码得扛得住折腾啊这里有个细节得注意。property下面那个方法名就是对外暴露的属性名。比如我上面写的def radius(self)那外面就用.radius访问。然后setter的写法是radius.setter这个radius必须和前面那个方法名完全一致不然Python会一脸懵逼。四、实战案例电商系统的价格保卫战回到我开头说的那个坑。用property重构后代码长这样classProduct:definit(self,name,price):self._namename self._pricepricepropertydefprice(self):获取价格时自动保留两位小数强迫症福音returnround(self._price,2)price.setterdefprice(self,value):设置价格时多重校验产品经理再也没法挑刺ifnotisinstance(value,(int,float)):raiseTypeError(价格必须是数字别给我传字符串)ifvalue0:raiseValueError(价格不能为负数咱不做赔本买卖)ifvalue999999:raiseValueError(价格离谱了这卖的是黄金吗)self._pricefloat(value)propertydefname(self):商品名自动转大写品牌部要求returnself._name.upper()name.setterdefname(self,value):ifnotvalueorlen(value.strip())0:raiseValueError(商品名不能为空)self._namevalue.strip()业务代码完全不用改phoneProduct(iPhone 17,8999)print(phone.price)# 输出8999phone.price7999# 正常打折phone.price-100# 直接报错拦截脏数据print(phone.name)# 输出IPHONE 17自动大写这段代码我现在看着都爽。三个校验规则类型检查、负数检查、上限检查全塞进setter里业务方调用的时候完全无感知。而且getter里我还加了round处理解决浮点数精度问题0.10.2不等于0.3那种坑。这种润物细无声的增强才是真正的Pythonic五、只读属性让某些数据只准看不准摸有时候咱们希望某个属性只能读不能改。比如用户的id或者创建时间这些一旦生成就该锁死。咋搞很简单只写getter不写setter。Python会自动把这个属性变成只读classUser:definit(self,user_id):self._user_iduser_id self._created_at2025-04-13 14:30:00propertydefuser_id(self):returnself._user_idpropertydefcreated_at(self):returnself._created_atuUser(9527)print(u.user_id)# 正常输出9527u.user_id8866# 报错AttributeError: cant set attribute想删除属性还可以加deleter虽然用得少但得知道user_id.deleterdefuser_id(self):delself._user_idprint(用户ID已删除数据脱敏完成)不过说实话deleter我工作这么多年用过的次数……不超过5次。大部分时候咱们还是get/set用得多。六、property 的隐藏技能计算属性除了校验数据property还能做动态计算。比如你想实时获取年龄但只存生日或者想实时算 BMI但只存身高体重。这种派生数据用property绝配fromdatetimeimportdatetimeclassPerson:definit(self,birth_year):self._birth_yearbirth_yearpropertydefage(self):年龄实时计算每年自动涨一岁不用维护current_yeardatetime.now().yearreturncurrent_year-self._birth_yearpropertydefbirth_year(self):returnself._birth_yearpPerson(1990)print(f今年{datetime.now().year}岁)# 输出今年35岁注意age没有setter因为是计算出来的改它没意义这种写法比手动算年龄优雅100倍而且每次访问.age都是实时结果不存在数据过期的问题。2025年最新的Python 3.13里property的性能还做了进一步优化计算属性的开销几乎可以忽略。七、踩坑指南这些坑我帮你踩过了用了这么多年property我也总结了一些血泪教训千万别在getter里改数据曾经有个同事在property的getter里加了日志记录还顺便改了计数器。结果一调试发现数据对不上因为每次访问属性都会触发getter副作用太多了。getter就该纯读取别搞事情setter里的类型检查要趁早Python是动态类型传啥都有可能。建议用isinstance()做类型校验不然传个None进去后面报错信息会把你带偏到怀疑人生。别滥用property不是所有属性都需要包装。简单的、不需要校验的字段直接self.xxx xxx就行。过度封装反而让代码显得装。记住需要加逻辑的时候再上property不要为了用而用。继承时要小心如果在子类里重写父类的property要注意setter和getter是绑定的。重写getter的时候如果不小心可能会把setter给覆盖没了。这种情况……建议用传统方法或者super()处理别硬刚。八、结语property 真香说实话刚开始学property的时候我觉得这玩意儿有点魔法不够直观。但经历过那次3万行代码的重构惨案后我彻底真香了。它完美解决了既要封装安全又要调用简洁的矛盾让Python的面向对象编程既有Java的严谨又不失Python的优雅。在2025年的今天Python 3.12/3.13已经发布property的性能和稳定性都达到了新高度。不管你是写Web后端、数据分析还是搞AI模型封装掌握这个装饰器都能让你的代码质量上一个台阶。最后灵魂拷问一句你现在的项目里有多少本应该用property却没用的裸奔属性 回去翻翻代码说不定能发现一堆隐患如果这篇帮你少踩了一个坑记得点个赞咱们评论区聊聊你遇到过最离谱的属性校验需求是啥我上次遇到个要求价格必须是质数的……产品经理的脑洞不服不行P.S. 目前国内还是很缺AI人才的希望更多人能真正加入到AI行业共同促进行业进步增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow教程通俗易懂高中生都能看懂还有各种段子风趣幽默从深度学习基础原理到各领域实战应用都有讲解我22年的AI积累全在里面了。注意教程仅限真正想入门AI的朋友否则看看零散的博文就够了。