对此,python提供了解决方案:
经过这个行为后,被装饰函数的系统变量问题被解决了
输出结果为
刚才的例子都比较简单,被装饰的函数是没有参数的 。如果被装饰的函数有参数 , 只需要在定义装饰行为时(事实上,这个才更通用),增加(*args, **kwargs)描述即可
之前的描述中可以感受到,对于例子中的装饰行为(前后加打印),函数被装饰后,本质上是调用了新的装饰函数wrap_func 。
因此 , 如果原函数需要有输入参数传递,只需要在wrap_func(或其他任意名字的装饰函数)定义时,也增加参数输入(*args, **kwargs),并将这些参数,原封不动地传给待装饰函数f 。
这种定义装饰行为的方式更具有普遍性,忘记之前的定义方式吧
我们试一下
输出
这里需要注意的是,如果按照以下的方式定义装饰器
那么以下语句将不会执行
因为装饰后实际的函数wrap_func(虽然名字被改成了原函数,系统参数也改成了原函数),运行到return f(*args, **kwargs) 的时候已经结束了
因为装饰器my_decorator本身也是可以输入的 , 因此,只需要在定义装饰器时,增加参数 , 并在后续函数中使用就可以了,比如
此时装饰器已经可以有输入参数了
输出
你可能发现,为什么不用简写版的方法了
因为以上代码会报错?。?
究其原因,虽然
等价于
但是,
并不等价于
这本身和@语法有关,使用@my_decorator时,是系统在应用一个以单个函数作为参数的闭包函数 。即 , @是不能带参数的 。
但是你应该发现了,之前的@wraps(f)不是带参数了吗?请仔细观察以下代码
通过一层嵌套,my_decorator_with_parma本质上是返回了一个参数仅为一个函数的函数(my_decorator),但因为my_decorator对my_decorator_with_parma来说是一个闭包,my_decorator_with_parma是可以带参数的 。(这句话真绕)
通过以上的定义 , 我们再来看
可以这么理解,my_decorator_with_parma(msg='yusheng')的结果是原来的my_decorator函数,同时,因为my_decorator_with_parma可以传参,参数实际上是参与了my_decorator的(因为my_decorator对my_decorator_with_parma是闭包),my_decorator_with_parma(msg='yusheng')全等于一个有参数参加的my_decorator
因此 , 以上代码等价于有参数msg传递的
比较绕,需要理解一下,或者干脆强记这种范式:
以上范式包含函数的输入输出、装饰器的输入,可以应对大部分情况了 。
实验一下:
输出
以上是一个log装饰器,利用datetime统计了函数的耗时,
并且,装饰器可以进行输出文件操作,如果给出了文件路径,则输出文件,否则就打印 。
利用这个装饰器,可以灵活地进行耗时统计
不设置输出文件地址,则打印 。运行结果为:
也可以输出到文件
输出结果为
同时在当前目录生成了一个test.log 文件,内容为:
以上的装饰器都是以函数形式出现的 , 但我们可以稍做改写,将装饰器以类的形式实现 。
这个装饰器类Log 上个例子里的装饰器函数log功能是一样的,同时,这个装饰器类还可以作为基类被其他继承,进一步增加功能 。
原文
python装饰器使用 装饰器是从英文decorator翻译过来的,从字面上来看就是对某个东西进行修饰,增强被修饰物的功能,下面我们对装饰器做下简单介绍 。
一、怎么编写装饰器
装饰器的实现很简单 , 本质是一个可调用对象 , 可以是函数、方法、对象等,它既可以装饰函数也可以装饰类和方法,为了简单说明问题,我们实现一个函数装饰器,如下代码:
推荐阅读
- 抗险救灾的体育游戏,有趣的抗洪抢险游戏
- phpmysql分页控制显示页数,php实现分页显示
- 电商公司如何管理员工,电商公司人员
- linux命令不好用 linux 命令失效
- css不换行样式,Css不换行
- 组装电脑都需要买什么,组装电脑需要买什么线
- 模拟大自然哪个游戏好玩,模拟大自然游戏视频解说
- 清除按钮java代码 清除命令按钮代码编写
- SAP预提,Sap预提费用