Python 动态属性:能用一个参数搞定的,就不用两个

2022-10-25 20:57:07 浏览数 (3)

Python 有个魔法函数 __getattr__,可以在调用对象的某个属性时自动执行,利用这一点,我们可以实现非常灵活的功能。

举个例子,计算两个数的加减乘除,只需要传入一个参数就可以进行计算:

文件:dynamic_attr_of_class.py 的内容如下:

代码语言:javascript复制
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 的内容如下:

代码语言:javascript复制
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__ 还能实现哪些神奇的事情,欢迎留言分享

0 人点赞