Python 这个语言吧,有一个特别灵活也特别“阴间”的地方,就是它可以在运行时动态操作对象的属性。说得直白点,就是你可以随便加属性、改属性、查属性,甚至删属性,而且不报错,Python 也不会嫌你烦。这在很多静态语言比如 Java、C++ 那边根本是不可想象的。
那这事咋做呢?核心其实就两个函数:getattr() 和 setattr(),再加上一个兄弟 hasattr() 和一个扫地出门用的 delattr(),基本上这几个组合拳一套下来,对象的属性你想咋整就咋整。
我第一次意识到这个特性的厉害,是在一个项目里搞动态配置加载的功能。当时业务要求是根据用户的不同角色,动态地给某个配置类添加属性。你说这个配置用字典不就完事了?是的,我当时也这么干了,结果后来业务又说,要支持“属性点语法”,就是 config.user_timeout 这种写法。我一听,完了,这不是典型的类属性访问嘛,字典不行了。
后来我就翻源码,研究怎么优雅地把字典转成支持属性访问的对象。这时候我才真正体会到 Python 的“魔性”。
先说 getattr(obj, attr_name),这个函数你给它一个对象,一个属性名,它就老老实实地把值给你找出来。如果没有?它不会报错,但你可以设个默认值,比如:
这行代码的意思是,如果 config 有个 user_timeout 属性,那就用它的值;如果没有,就用默认的 30。这玩意儿真是做配置读取的神器,和字典的 .get() 方法有得一拼。
再说 setattr(obj, attr_name, value),这就更野了。你可以直接给对象硬塞一个属性进去,不管之前有没有,比如:
执行完这句之后,config.max_retries 就合法了,访问它就是 5。这种能力在做反射、插件系统、ORM 框架的时候特别有用。比如你写一个动态表单类,根据表单字段生成对应的属性,靠的就是这招。
我记得我搞一个插件系统的时候,插件有很多自定义配置项,用 YAML 写的,我一开始还傻傻地一个个手写,然后突然灵光一闪,直接上 setattr() 循环灌属性,插件瞬间从“死板”变“活灵活现”。有点像在给对象装外挂一样,想怎么改就怎么改。
不过呢,setattr() 有个坑,必须得注意:你改的是对象属性,不是类属性。而且,如果你用的是 __slots__ 限制的类,那你想随便加属性,对不起,加不了,会报错。这算是 Python 给自由加了个“护栏”,要不然真的谁都能拿对象当字典用了,那多恐怖。
还有一个小兄弟叫 hasattr(obj, attr_name),这就是个布尔检查器,看看属性存不存在,用来防呆防炸是必须的:
特别是在你处理外部数据,比如 json、数据库字段、用户输入的时候,这种检查就像安全带,帮你避免一头撞南墙。
最后一个 delattr(obj, attr_name),这个就比较暴力了,直接把属性删掉。它跟 del obj.attr_name 是一样的,只不过可以动态传属性名。这在做缓存失效、清理无用属性的时候挺方便。
那你可能要问了,这几个东西就这么简单?为啥能搞出这么多花活儿来?
其实背后就是 Python 的对象模型太灵活了。你可以把对象看成一个属性字典(虽然不完全是,但本质很像),这些函数就是你操作这个“字典”的接口。比如你可以写个循环,把一堆键值对塞进对象里:
这操作跟 obj.__dict__.update(data) 类似,但更安全,而且对 __slots__ 类型的类也更通用一点(当然它会报错,但你可以 try 一下再 fallback)。
我曾经在给公司搞一个数据同步服务的时候,就用过这个技巧。因为我们从多个第三方系统拉过来的数据字段五花八门,有的系统字段多,有的少,结构还不固定。用传统的类建模根本 hold 不住,最后我就搞了个“属性包”对象,靠 setattr() 动态赋值,兼容性杠杠的。
当然了,这种动态属性的方式,虽然灵活,但也不是没有代价的。最大的代价就是代码可读性差,调试不方便,IDE 提示全靠猜,type checker 直接放弃治疗。你用 getattr()、setattr() 多了,别人一看你的代码就一脸懵逼:“这属性哪来的?”、“这函数哪儿定义的?”——尤其在多人协作的时候,这就是一把双刃剑。
所以我的建议是:这种操作,能不用就不用,除非你明确知道自己在干嘛,比如做框架、做底层库、做 DSL,这种需要高动态能力的场景再用。普通业务开发里,能写明白的就不要搞花活儿,写得越动态,出事的可能性就越高。
还有一点,就是性能。动态访问属性比直接访问要慢一丢丢,因为多了一层查找逻辑。虽然差距不是特别大,但在极端高频场景下,还是能拉开差距的。如果你是搞高性能服务的,尤其是 asyncio 那一挂的,别因为一两个 getattr() 把延迟拉高了,那可太亏了。
总结一句话:Python 的动态属性机制确实很香,用得好是大杀器,用不好就是自杀工具。该刚就刚,该动态就动态,别滥用。
行了,今天这点就聊到这儿。下次我有空再跟你们聊聊 __getattr__ 和 __getattribute__,那可是更深一层的魔法操作,简直可以玩出“代理人”的感觉,拦截所有属性访问的请求,像黑客一样控制一切。但那是进阶版,今天先打住,消化一下这些基本功吧。
以上就是“Python中如何动态获取和设置对象的属性?”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://www.phpxs.com/post/13291/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料