一、装饰器组成
1.1 高阶函数
高阶函数代表函数作为一个值来进行调用,也成为函数调用函数。
1 def test1():2 print("hello")3 def test2(d):4 print("world")5 test2(test1())
输出结果为:
hello
world1.2 嵌套函数
嵌套函数就是指的函数套函数。
1 def test1():2 def func():3 print("hello")4 return func()5 test1()
输出结果为:
hello二、装饰器
1、装饰器介绍
装饰器本质上也是函数,其功能是为被装饰的函数添加附加功能。装饰器是由高阶函数和嵌套函数组成。
装饰器的使用原则:
(1)不能修改被装饰函数的源代码;
(2)不能修改被装饰函数的调用方式
总之,装饰器对被装饰函数来说是透明的。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
函数
2、装饰器举例
函数即变量:
1 def test():2 print("hello")3 a=test4 a()
结果输出:
hello
统计一个函数的执行时间
1 import time 2 def bar(): 3 time.sleep(4) 4 print("haha ni hao") 5 def test1(func): 6 start_time=time.time() 7 func() 8 stop_time=time.time() 9 print("the func run time is %s" % (stop_time - start_time))10 test1(bar)
输出结果:
haha ni hao
the func run time is 4.0002288818359375
简单装饰器
1 import time 2 def timmer(func): 3 def deco(): 4 start_time=time.time() 5 func() 6 stop_time=time.time() 7 print("the func run time is %s" % (stop_time - start_time)) 8 return deco() 9 @timmer10 def bar():11 time.sleep(4)12 print("haha ni hao")
输出结果:
haha ni hao
the func run time is 4.0002288818359375装饰器传参:
1 import time 2 def timer(func): 3 def deco(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print("the func run time is %s" % (stop_time - start_time)) 8 return deco 9 @timer10 def test1():11 time.sleep(4)12 print("haha is test1")13 @timer14 def test2(name,age):15 print("name is %s,age is %s"% (name,age))16 test1()17 test2('shuaiguo',20)
输出结果:
haha is test1
the func run time is 4.000228643417358name is shuaiguo,age is 20the func run time is 0.0三、生成器&迭代器
迭代器:
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
1.访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
2.不能随机访问集合中的某个值 ,只能从头到尾依次访问
3.访问到一半时不能往回退
4.便于循环比较大的数据集合,节省内存
可以直接作用于for
循环的数据类型有以下几种:一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。可以使用isinstance()
判断一个对象是否是Iterable
对象:
1 from collections import Iterable2 print (isinstance([],Iterable))3 print (isinstance({}, Iterable))4 print(isinstance('abc', Iterable))5 print(isinstance((x for x in range(10)), Iterable))6 print(isinstance(100, Iterable))
输出结果:
TrueTrueTrueTrueFalse生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数.
生成器:
定义: 一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器
列表在使用前数据就已经生成了,但是我们往往只使用其中一部分数据,大部分数据用不到浪费空间。生成器generator只有在调用时才生成相应的数据。
创建一个简单的生成器:
g=(x*x for x in range(1,11)) print(g)生成结果:<generator object <genexpr> at 0x00000000006A5A40>创建list
和generator
的区别仅在于最外层的[]
和()。list的元素我们可以一个个打印出,如果要打印generator中的元素需要借助next方法。
输出生成器里面的内容:
1 g=(x*x for x in range(1,11))2 print(next(g))3 print(next(g))4 print(next(g))5 for i in g:6 print(i)
generator保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。可以通过for
循环来迭代它,并且不需要关心StopIteration
的错误。从下面的结果我们也可以看出for循环并没有从头开始输出而是接着第三个Next的值开始输出。
输出结果:
149162536496481100
斐波拉契数列:
1 def fib(max):2 n, a , b = 0,0,13 while n < max:4 print(b)5 a,b=b,a+b6 n+=17 return 'done'8 fib(10)
输出结果:
1
1235813213455注意赋值语句:
a,b =b, a+b相当于:
t=(b,a+b) #t是一个元组
a=t[0]
b=t[1]
仔细观察,可以看出,fib
函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib
函数变成generator,只需要把print(b)
改为yield b
就可以了:
1 def fib(max): 2 n, a , b = 0,0,1 3 while n < max: 4 yield b 5 a,b=b,a+b 6 n+=1 7 return 'done' 8 f=fib(6) 9 print(f)10 print(f.__next__())11 print(f.__next__())12 print(f.__next__())
这是定义generatoe的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就是一个生成器。
结果输出:<generator object fib at 0x0000000000AF5A40>
112generator和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
1 import time 2 def consumer(name): 3 print("%s 准备吃包子啦!" % name) 4 while True: 5 baozi = yield #碰到yield退出程序,遇到c.__next__()或者(send)时在进来继续往下走(只要有yield就是生成器) 6 print("包子【%s】来了,被【%s】吃了!" %(baozi,name)) 7 def producer(name): 8 c=consumer('zj') 9 c2 = consumer('haha')10 c.__next__() #输出zj准备吃包子了11 c2.__next__() #输出haha准备吃包子了12 print("我%s开始准备做包子了!" % name) #输出我开始做包子了13 for i in range(3): #循环14 time.sleep(1) #sleep 1秒15 print("做了1个包子") #做了一个包子16 c.send(i) #将i的值传给yield17 c2.send(i) #将i的值传给yield18 producer('csp') #调用函数
输出结果:
zj 准备吃包子啦!haha 准备吃包子啦!我csp开始准备做包子了!做了1个包子包子【0】来了,被【zj】吃了!包子【0】来了,被【haha】吃了!做了1个包子包子【1】来了,被【zj】吃了!包子【1】来了,被【haha】吃了!做了1个包子包子【2】来了,被【zj】吃了!包子【2】来了,被【haha】吃了!