python装饰器

目录

1.闭包 2.nonlocal 3.装饰器

1.闭包 <a id='01'></a>

当一个函数 inner 能够使用 outer函数的变量时,称inner为闭包:

1# 演示闭包 2def outer(): 3 i = 4 4 5 def inner(): 6 sum = i + 1 7 print(sum) 8 9 return inner # 注意这里是函数名(指代函数地址);不是inner(),inner()表示函数调用。 10 11 12f1 = outer() 13print(f1) # 此时 f1 指代函数地址,还未运行 14# print(f1()) 15f1() # 调用运行f1函数,等同于 outer()()

运行结果 演示闭包运行结果 闭包特点:

  • 函数outer() 内部再嵌套函数inner();
  • 内部函数inner() 使用了外部函数outer() 的变量 i;
  • 外部函数outer() 返回内部函数的函数名inner。

2.nonlocal <a id='02'></a>

nonlocal是关键字,声明了非局部(non-local)也非全局(non-global)的变量,例如闭包函数inner外的函数;变量跟着函数存在而存在,跟着函数销毁而销毁。 它允许我们在inner函数内部 修改outer函数的i变量:

1def outer(): 2 i = 4 3 def inner(): 4 nonlocal i # 声明变量i的作用域 5 sum = i + 1 6 i += 1 7 print(sum) 8 return inner 9f1 = outer() 10for i in range(5): 11 # 使用for循环运行5次 12 f1()

运行结果: image 可以看出5次运行,每次i的值都加了1;直到结束。而把 nonlocal i注释掉会报错,在注释掉i+=1则不会报错: image

3.装饰器 <a id='03'></a>

当一个函数 inner 能够使用 outer函数的变量,当这个变量是一个函数时,这个闭包就是一个装饰器。 在定义一个类时,使用@classmethod和@staticmethod修饰方法,这样的写法就是闭包的语法糖。

1# 1.创建一个统计函数运行次数的装饰器 2def func_count(func): 3 a = 0 # 函数初始值 4 def inner(str):# 传入函数及其参数 5 nonlocal a # 在内部函数修改外部函数的变量 6 a += 1 7 func(str) # 运行传进来的函数 8 print(f'执行了{a}次!') # 函数每运行一次就提示一次 9 return inner 10 11# 2.定义输出函数并使用装饰器 12@func_count 13def f1(str): 14 print(str) 15 16# 3.执行函数 17for i in range(5): 18 f1('hello world')

运行结果: image 可以看出装饰器的特点与闭包差不多:

  • 有函数嵌套;
  • 内部函数使用了外部函数的变量,这个变量可以是函数;
  • 外部函数返回内部函数的函数名
  • 为原来的f1函数增加了新的功能:可以查看执行次数。

多个装饰器

一个函数可用多个装饰器来装饰,在定义一个装饰器;

1# 创建统计函数执行时间的装饰器 2import time 3def func_time(func): 4 time_count = 0 5 def inner(str): 6 nonlocal time_count # 在内部函数修改外部函数的变量 7 time_start = time.time() #记录开始时间 8 func(str) 9 time_count += time.time() - time_start #新的总运行时间=旧的总运行时间+本次执行时间 10 print(f'总执行用时{time_count}') 11 return inner

在原来的基础上改造 f1函数:

1@func_time 2@func_count 3def f1(str): 4 a = 0 5 for i in range(100000): 6 a += 1 # 模拟函数运行时间 7 print(f'{str}-{a}')

同上运行5次 f1函数,运行结果: image

带有参数的装饰器

在为原来函数添加装饰器时,可对装饰器传入参数;具体实现就是三层嵌套的函数:

1# 定义带有参数的装饰器 2def parameter(n): # 传入装饰器参数 3 def outer(func): 4 def inner(*args, **kwargs): # 传入可变参数或不定长参数,*元组类型参数(1,2,3);**字典类型参数(a=1,a=2,a=3) 5 for i in range(n): 6 result = func(*args, **kwargs) 7 return result # 如果func没有返回值可以省略不写 8 return inner 9 return outer 10 11@parameter(5) 12def f1(str): 13 print(f"Hello {str}!") 14 15f1("World")

运行结果: image

点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

编写一个闭包函数,要实现的功能是计数功能

大家好,我是皮皮。一、前言前几天在Python最强王者交流群有个叫【杰】的粉丝问了一个Python装饰器的问题,这里拿出来给大家分享下,一起学习下。二、解决过程这里【东哥】给出了解答,其实这个题目就是在考你装饰器的内容。代码如下:count0defwrapper(func):definner(args,kwargs):g

python装饰器详解

你会Python嘛?我会!那你给我讲下Python装饰器吧!Python装饰器啊?我没用过哎以上是我一个哥们面试时候发生的真实对白。\分割线

Python Challenge Level 18

初学Python,挑战一下流行的PythonChallenge,很不幸,卡在了18关~~被字符字节码之间的转换搞得焦头烂额,不过终于搞定了还是很happy的~~~主要的问题就是16进制形式的字符如何转成字节码(注意:不是encoding)如:\'89','50','4e','47','0d','0a','1a','0a','00

Python3:sqlalchemy对mysql数据库操作,非sql语句

Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''