Python 有个魔法函数 __getattr__
,可以在调用对象的某个属性时自动执行,利用这一点,我们可以实现非常灵活的功能。
举个例子,计算两个数的加减乘除,只需要传入一个参数就可以进行计算:
文件:dynamic_attr_of_class.py
的内容如下:
class DynamicAttr(object):
def __getattr__(self, name):
op, num = name.split("_")
num = int(num)
return {
"times": lambda val: val * num,
"plus": lambda val: val num,
"minus": lambda val: val - num,
"dividedby": lambda val: val / num,
}[op]
if __name__ == "__main__":
da = DynamicAttr()
assert da.plus_10(13) == 23
assert da.times_10(13) == 130
assert da.minus_10(13) == 3
assert da.dividedby_10(13) == 1.3
上面的代码,当调用 da.plus_10
的时候,就会调用到 __getattr__
。执行 op, num = name.split("_")
后,op = 'plus', num = 10。
最后返回的是一个 lambda 函数,参数就是 val,因此 da.plus_10 相当于 lambda val: val 10,因此 da.plus_10(13) 就是 13 10 = 23。
从 Python 3.7 开始,__getattr__
不仅可以为类提供动态属性,也可以为模块提供动态属性。
上面 __getattr__
函数可以直接定义在模块(一个 Python 文件)里,比如说文件 dynamic_attr_of_module.py
的内容如下:
def __getattr__(name):
op, num = name.split("_")
num = int(num)
return {
"times": lambda val: val * num,
"plus": lambda val: val num,
"minus": lambda val: val - num,
"dividedby": lambda val: val / num,
}[op]
在另一个文件 main.py 中,就可以这样来使用:
代码语言:javascript复制import dynamic_attr_of_module as da
if __name__ == "__main__":
assert da.plus_10(13) == 23
assert da.times_10(13) == 130
assert da.minus_10(13) == 3
assert da.dividedby_10(13) == 1.3
是不是很方便,很灵活呢?
最后的话
本文分享了如何利用 Python 的动态属性来实现一些酷炫的函数:比如说减少函数的参数。你也可以思考一下,这个 __getattr__
还能实现哪些神奇的事情,欢迎留言分享。