学Python装饰器那阵子,我真的快被逼疯了。看着网上的教程,什么高阶函数,什么闭包,什么语法糖,每个词我都认识,连在一起就完全看不懂。我甚至怀疑自己是不是脑子不好使。
直到有一天,我在B站刷到一个动画演示。那个视频用了一个很简单的场景:一个函数就像一台自动售货机,你投币进去,它掉出饮料。装饰器呢,就是在售货机外面套了个箱子。这个箱子不改变售货机本身,但能在你投币之前检查一下硬币是不是真的,在饮料掉出来之后给你加个杯垫。
那一刻我直接愣住了。原来这么回事?
我试着用自己的话重新说一遍。装饰器本质上就是一个函数,它吃掉另一个函数,然后吐出一个增强版的新函数。这个新函数跟原来的函数长得很像,但多了点东西。比如你写了个打印日志的函数,想在每次调用时记录时间。常规做法是在每个函数里都加一行print(time.time())。但有了装饰器,你只需要写一个装饰器,然后轻轻地在函数头上加一行@log_time。
关键是,你根本不用改动原来的函数代码。这就像你有一把普通的椅子,想让它变高一点,不用把椅子腿锯了重接,只需要在椅子下面垫个垫子就行。装饰器就是那个垫子。
我还记得那个动画里演示了装饰器的执行顺序。两个装饰器叠在一起,从外向内包裹,然后从内向外执行。这个顺序我以前总记混。但动画里画得很清楚:装饰器像洋葱皮,一层套一层。调用的时候,先走进最外层,再到内层,最后到达核心函数。返回的时候反过来。
我按照自己的理解写了一段代码。
def my_decorator(func): def wrapper():
print('在函数执行前做点事')
func()
print('在函数执行后做点事')
return wrapper
@my_decorator
def say_hello():
print('你好')
say_hello()
运行结果:
在函数执行前做点事
你好
在函数执行后做点事
看着这个输出,我心里一下子就踏实了。原来之前看不懂,不是因为难,是因为我没找到对的解释方式。那些教科书式的解释太抽象了,什么“返回函数的函数”,什么“元编程”,普通人根本get不到。
后来我又试着用装饰器做了一些实用的事。比如检查用户是否登录,比如缓存计算结果,比如记录函数运行时间。每写成一个,我就觉得Python这门语言的设计真的很巧妙。装饰器让我可以像搭积木一样扩展函数的功能,而不需要把代码搞得乱七八糟。
如果你现在也卡在装饰器这里,我建议你去找找可视化的讲解。文字看不懂,那就看图。图看不懂,那就看动画。有时候换个角度,事情一下子就通了。Python没那么玄乎,它只是需要你用一个合适的方式去理解它。