当前位置: 首页 > 科技观察

为什么装饰器这么难理解?

时间:2023-03-14 17:51:12 科技观察

装饰师的话题无论是项目还是面试都离不开。装饰器的强大之处在于可以在不修改原有业务逻辑的情况下,对代码进行扩展,如权限验证、用户认证、日志记录、性能测试等。、事务处理、缓存等是装饰器最好的应用场景,可以最大程度的复用代码。但是为什么初学者理解装饰器这么难呢?我认为这是因为他们不了解Python函数,因为装饰器本质上是函数。函数的定义在了解装饰器之前,您需要了解函数的工作原理。先从最简单的函数定义说起:defffoo(num):returnnum+1定义了一个名为foo的函数,foo也可以理解为变量名,变量指向一个函数对象。调用函数只需要在函数名后面加上括号,并传递必要的参数(如果定义函数时有参数)value=foo(3)print(value)#4变量名foonow指向一个函数对象,但它也可以指向另一个函数。defbar():print("bar")foo=barfoo()#bar函数作为返回值在Python中,万物皆对象,函数也不例外。可以像整数一样作为其他函数的返回值,例如:defffoo():return1defbar():returnfooprint(bar())#print(bar()())#1#相当于打印(foo())#1bar()的返回值是一个函数对象,所以我们可以继续对返回值进行调用。调用bar()()等同于调用foo(),因为变量foo指向的对象与bar()的返回值是同一个对象。函数作为参数函数也可以像整数一样作为函数的参数,例如:defffoo(num):returnnum+1defbar(fun):returnfun(3)value=bar(foo)print(value)#4函数bar接收一个parameter,这个参数是一个可以被调用的函数对象。当函数foo被传递给bar时,foo和fun这两个变量名指向同一个函数对象。所以调用fun(3)等同于调用foo(3)。函数嵌套函数不仅可以作为参数和返回值,函数也可以定义在另一个函数中,作为嵌套函数存在,例如:defouter():x=1definner():print(x)inner()outer()#1inner是嵌套函数,可以访问外层函数的变量。当调用外部函数时,会发生3件事:将值1赋给变量x并定义嵌套函数inner。这个时候,inner里面的代码是不会执行的。因为这个函数还没有被调用,直到第3步调用了inner函数,才会执行inner中的代码逻辑。再看一个闭包的例子:defouter(x):definner():print(x)returninnerclosure=outer(1)closure()#1也是一个嵌套函数,只是稍微修改一下,传递的是局部变量x作为参数进来,函数中不再直接调用嵌套函数,而是作为返回值返回。这里的闭包是一个闭包,本质上还是一个函数。闭包是一个引用自由变量(x)的函数(内部)。装饰器继续往下看:defffoo():print("foo")上面的函数可能是史上最简单的业务代码。虽然没用,但能说明问题。现在,有一个新的需求,需要在执行这个函数的时候添加一个日志:defffoo():print("loggingstarts")print("foo")print("loggingends")函数实现,唯一的问题就是就是需要侵入原代码,增加日志逻辑。如果有几十个这样的函数需要添加日志,这个是必须要做的。显然,这样的代码根本不是Pythonic的。那么是否可以在不提前修改业务代码的情况下实现日志功能呢?答案是装饰器。defouter(func):definner():print("loggingstarts")func()#Businessfunctionprint("loggingends")returninnerdeffoo():print("foo")foo=outer(foo)foo()I没有修改foo函数中的任何逻辑,只是重新分配foo变量以指向一个新的函数对象。***调用foo()不仅打印了日志,还完成了业务逻辑的执行。下面我们来分析一下它的执行流程。这里的外层函数其实就是一个装饰器。装饰器是一个闭包,它接受一个函数作为参数并返回一个新函数。本质上,装饰器也是一个函数。外层函数的返回值就是内层函数。函数内部除了进行日志操作外,还有业务代码。函数重新赋值给foo变量后,调用foo()等同于调用inner()。foo被重新赋值前:赋值后:另外,Python为装饰器提供了语法糖@,在函数定义处使用:@outerdeffoo():print("foo")foo()这样省去了手动的步骤重新分配foo。不知道这里的装饰器你懂吗?当然,装饰器可以更复杂一些,比如可以接受参数的装饰器、基于类的装饰器等等。【本文为专栏作家“刘志军”原创文章,作者微信公众号:Python之禅(VTtalk)】点此阅读更多本作者好文