权威网站有哪些,wordpress是可视化编辑,网站放到iis如何做指向,个人做电影网站合法吗Python 装饰器初探 在谈及Python的时候#xff0c;装饰器一直就是道绕不过去的坎。面试的时候#xff0c;也经常会被问及装饰器的相关知识。总感觉自己的理解很浅显#xff0c;不够深刻。是时候做出改变#xff0c;对Python的装饰器做个全面的了解了。 1. 函数装饰器 直接上… Python 装饰器初探 在谈及Python的时候装饰器一直就是道绕不过去的坎。面试的时候也经常会被问及装饰器的相关知识。总感觉自己的理解很浅显不够深刻。是时候做出改变对Python的装饰器做个全面的了解了。 1. 函数装饰器 直接上代码看看装饰器到底干了些什么 from functools import wraps
import timedef time_cost(func):wraps(func)def f(*args, **kwargs):start_time  time.time()func(*args, **kwargs)end_time  time.time()print(end_time - start_time)return ftime_cost
def test(*args, **kwargs):time.sleep(1.0)if __name__  __main__:test()上面的Python代码运行后会给出test函数的执行时间。代码的执行顺序大概如下首先是将test作为值传递给time_cost函数返回函数f然后再调用f这是带有time_cost装饰器的test函数的大致执行过程。 从中不难看出即使不使用装饰器符号我们利用Python的语言特性也能达成上述目的。用装饰器符号的好处是简化了代码增加了代码的可读性。 这是一段非常简单的对函数使用装饰器的Python代码。等等wraps(func)是什么鬼悄悄干了什么哇 我们稍微修改下上述代码结果如下 from functools import wraps
import timedef time_cost(func):def f(*args, **kwargs):start_time  time.time()func(*args, **kwargs)end_time  time.time()print(end_time - start_time)print(hello world)return ftime_cost
def test(*args, **kwargs):time.sleep(1.0)if __name__  __main__:print(test.__name__) 发现输出了hello world同时输出test.__name__居然变成了f并不是我们预期的test。根据这样的输出结果我们不难得出其实被装饰器time_cost修饰过的函数test本质上已经等同于time_cost(test)此时访问test.__name__实际上访问的是time_cost(test).__name__得到的当然就是f啦。当我们加上wraps(func)此时test.__name__变成了test。 下面介绍带参数的装饰器更加难了。在谈论带参数的装饰器之间首先得引入一个概念那就”闭包“。如果你以前用过脚本语言比如JavaScript那么一定会很熟悉闭包这个概念。下面是一个闭包样例 def add(a):def wrapper(c):return a  creturn wrapperif __name__  __main__:add3  add(3)add9  add(9)print(add3(4)  7)print(add9(1)  10) 从中可以看出在调用add3的时候wrapper内部还可以访问到a的值这就是闭包的作用。理解了闭包理解带参数的装饰器就容易多了。 from functools import wrapsdef logging(level):def outer_wrapper(func):wraps(func)def inner_wrapper(*args, **kwargs):print([{level}]: enter function {func}().format(levellevel,funcfunc.__name__))return func(*args, **kwargs)return inner_wrapperreturn outer_wrapperlogging(levelWARN)
def show(msg):print(message:{}.format(msg))if __name__  __main__:show(hello world!)上面给出了一个带参数装饰器的示例。根据我们前面的铺垫我们不难分析得出上面的执行过程是logging(levelWARN)-outer_wrapper(show)-inner_wrapper()所以我们可以理解在被logging修饰后的show其实就是logging(levelWARN)(show)执行show(hello world!)其实就是在执行logging(levelWARN)(show)()。注意与不带参数的装饰器的区别带参数的装饰器比不带参数的装饰器多套了一层对应的装饰器也有了调用。因为在使用装饰器的时候带了括号所以装饰器本身多套了一层。被装饰器修饰过的函数在被调用的时候实际上执行的是装饰器最内层的函数其余层的在函数被修饰时就已经执行了。 是不是觉得非常自然对的我以前对装饰器的理解也就停留在不带参数的装饰器这一深度。 2. 基于类实现的装饰器 依然先上代码 from functools import wraps
import timeclass time_cost:def __init__(self, func):self.func  funcdef __call__(self, *args, **kwargs):start_time  time.time()result  self.func(*args, **kwargs)end_time  time.time()print(end_time - start_time)return resulttime_cost
def test(*args, **kwargs):time.sleep(1.0)if __name__  __main__:test()上面的基于类实现的不带参数的装饰器实际上利用的是Python中的可调用对象特性凡是实现了__call__方法的类的实例是可以被调用的。因此被time_cost修饰过的test函数本质上已经变成了time_cost类的实例了。调用test方法的时候实际上执行的是__call__方法。 下面介绍稍微复杂一点的基于类实现的带有参数的装饰器。 from functools import wrapsclass logging:def __init__(self, level):self.level  leveldef __call__(self, func):wraps(func)def wrapper(*args, **kwargs):print([{level}]: enter function {func}().format(levelself.level,funcfunc.__name__))return func(*args, **kwargs)return wrapperlogging(levelWARN)
def show(msg):print(message:{}.format(msg))if __name__  __main__:show(hello world!) 不同于基于类实现的不带参数的装饰器基于类实现的带参数的装饰器在__call__里面多了一层wrapper。被装饰器修饰的show方法本质上是logging(levelWARN)(show)此时调用show方法实际上执行的是wrapper方法。 现在看来其实装饰器也没有很复杂在实际的项目中用装饰器可以带来很大便利。 转载于:https://www.cnblogs.com/crackpotisback/p/10197698.html