Python技术迷

Python中的反射机制与动态特性

你有没有那种感觉,比如说,你家门口快递柜有一堆包裹,你根本不记得到底哪一个是你的,但扫码查一下快递号,马上就知道箱子在哪。Python 里头的反射其实跟这个巨像,很多人搞得好像什么“黑魔法”,其实就那回事。

举个例子吧,我们一般用 getattr、setattr 这些东西。小王那会还问我,哥,平时写代码不是直接调函数就完了,干嘛非得这样整?

就比如下面这个:

classDog:
defbark(self):
        print("汪汪汪")

d = Dog()
method_name = "bark"
getattr(d, method_name)()  # 你看,平时直接d.bark(),但有时候你方法名是字符串的时候只能这么来了

有时候你代码里那个方法名是外部传进来的,你写死不现实啊,就得用这种方式。还有比如你从配置文件里读出一堆方法名、属性名,动态给对象赋值,那就全靠反射这几个API了。

setattr 这个东西,真就跟家长给娃换名字似的

你想啊,比如说我有个对象,原来叫 name,现在突然想加个属性叫 age,平时你定义死在类里头是不可能的,得动态加:

setattr(d, "color", "黑白花")
print(d.color)  # 黑白花

就有点像家长给娃起个外号一样,随时想叫啥叫啥,属性名都能动态加,Python天生就不怎么管你——自由。

其实常用场景,平时自动注册啥的都得靠它

你们是不是有时候用Flask、Django什么的,看到那一堆路由注册都贼自动?其实底层就靠的这套机制。比如根据字符串去找到函数、类,然后动态加载起来,没反射你根本做不到。

有一次搞插件系统,就需要用户自定义实现某个接口,然后程序启动的时候自动去扫描一遍,把所有实现都挂上来,不可能手动写死对吧。其实Python的 importlib、__import__ 这些也是动态加载模块,说白了也是反射范畴。

动态特性?你可以把函数当变量随便塞

你要说最骚的,还是Python对象本身随便塞属性、塞方法。记得有次我们组那个小李,调接口要带一大堆动态参数,手写累死。最后直接上 **kwargs,再加上动态赋值属性:

classUser:pass
u = User()
for k, v in {"name": "Tom", "age": 24}.items():
    setattr(u, k, v)
print(u.name, u.age)  # Tom 24

你都不用提前写好 User 里有 name/age,反正有啥塞啥,动态就完事了。

一些常用的反射方法

小王老是忘,我一说就举栗子:

  • getattr(obj, "属性名", 默认值)
  • setattr(obj, "属性名", 值)
  • hasattr(obj, "属性名")
  • delattr(obj, "属性名")

别的没啥门槛,主要就是记住名字。反正我每次都得查,有时候脑子懵逼。

反正我吃过一次亏,就是动态加的方法如果是 lambda,调用起来有时候调不对。还有一点,getattr 如果找不到属性不加默认值会报错,这点记住。

对了,最近搞自动化批量调用的时候,经常用 getattr 动态调方法,一不小心写错名字,debug 半天,建议兄弟们加点日志,别栽坑里。

说到底,Python 这套动态反射,真的就是“你要啥,我就能给你啥”,你手里有字符串,啥都能变出来。至于元类、动态生成类这些骚操作,日常开发碰到不多,真遇到了再说呗。反正我一般也是等遇坑才现查。

-END-

我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领