1. 函数迭代器
yeald生成器,也是迭代器的一种
def frange(start, stop, step):
x = start
while x < stop:
yield x
x += step
for i in frange(10, 20 ,0.5):
print(i)
2.闭包
内部函数引用外部函数变量
定义内部函数后,使用return做外部函数返回值时,要返回内部函数的函数名称
def func():
a = 1
b = 2
return a + b
def sum(a):
def add(b):
return a+b
return add
#add 函数名称或函数的引用
#add()函数的调用
num1 = func()
num2 = sum(2)
print(num2(4))
def counter():
cnt = [0]
def add_one():
cnt[0] += 1
return cnt[0]
return add_one
num1 = counter()
print(num1())
3. 装饰器
首先定义一个time函数,判断当前函数运行了多少秒
import time
print(time.time())
def i_can_sleep():
time.sleep(3)
start_time = time.time()
i_can_sleep()
stop_time = time.time()
print("函数运行了 %s 秒" %(stop_time-start_time))
运行结果为:
1631667848.5058906
函数运行了 3.0053110122680664 秒
Process finished with exit code 0
一般函数的使用,但如果有大量的i_can_sleep()函数时,就要编写大量的这样的函数吗?当然不是,我们需要将大量重复性的只做一次,此时就可以使用装饰器来实现
装饰器怎么写了?在定义函数上面写一个@符号,后面写上要装饰i_can_sleep()函数的名称
#@timer叫做语法行,timer叫做装饰器中的装饰函数,i_can_sleep叫做被装饰函数
@timer
def i_can_sleep():
time.sleep(3)
把装饰函数和被装饰函数写好之后,就可以把之前额外的功能封装到装饰函数里面timer
将函数改写为
import time
#print(time.time())
def timer(func):
def warpper():
start_time = time.time()
func()
stop_time = time.time()
print("函数运行了 %s 秒" % (stop_time - start_time))
return warpper
#@timer叫做语法行,timer叫做装饰器中的装饰函数,i_can_sleep叫做被装饰函数
@timer
def i_can_sleep():
time.sleep(3)
#start_time = time.time()
i_can_sleep()
#stop_time = time.time()
#print("函数运行了 %s 秒" %(stop_time-start_time))
运行结果:
函数运行了 3.0034825801849365 秒
Process finished with exit code 0
发现用了装饰器和不用装饰器时的结果是一样的,区别在哪了?
会发现用了装饰器后,可以直接去使用i_can_sleep()函数,不用再写start_time和stop_time了,那么用了装饰器后的执行过程是怎么样的?
当调用i_can_sleep()函数时,发现上面有一个@timer装饰器,而@timer是来修饰i_can_sleep()函数的,所以python就是调用timer(i_can_sleep())函数,然后把i_can_sleep()函数传递到timer()函数中,timer()函数中接收一个func的变量,然后传递给内部函数,传递进来之后,内部的wapper函数定义了start_time和stop_time,然后把func()定义到中间,所以运行的时候,先执行start_time、func、stop_time、进行计算之后在进行输出,最后返回的时候返回内部函数的函数名。
可以看到装饰器和闭包是非常类似的,但是他们之间有什么区别了?
闭包穿进来的是变量,内部函数引用的也是变量
装饰器传进来的是一个函数,内部引用的也是一个函数
回到外部,timer(i_can_sleep)引用我们的i_can_sleep,引用完了之后会传递给一个指定的变量:num = timer(i_can_sleep),然后再用变量使用函数的方式num()
num = timer(i_can_sleep)
num()
但是这样的写法不是很简便,因此就演变成了@timer装饰器的写法,而下面直接运行的时候,不用写那么复杂的闭包的调用过程了,就是使用i_can_sleep(),就自动去找@timer装饰器
装饰器的使用
不带参数的装饰写法
def wai(func):
def nei():
start
func()
stop
return '内部函数返回值'
return '内部函数的名称'
带参数时要把参数传递进去
def tips(func):
def nei(a,b):
print('start')
func(a,b)
print('stop')
return nei
@tips
def add(a,b):
print(a+b)
针对不同函数的装饰器会不一样吗?就是给装饰器后面带上相应的参数
使用装饰器的好处:
1.调用函数时不用重复的编写修饰代码,可以放到装饰器里面
2.如果装饰器的代码需要复用时,可以用@装饰器的名字就可以
def new_tips(argv):
def tips(func):
def nei(a,b):
print('start %s %s' %(argv,func.__name__))
func(a,b)
print('stop')
return nei
return tips
@new_tips('add_module')
def add(a,b):
print(a+b)
@new_tips('sub_module')
def sub(a,b):
print(a-b)
print(add(4,5))
print(sub(7,3))def tips(func):
def nei(a,b):
print('start')
func(a,b)
print('stop')
return nei
运行结果:
start add_module add
9
stop
None
start sub_module sub
4
stop
None
4.自定义上下文管理器
使用with来实现上下文管理器
with open('name.txt') as f:
for line in f:
print(line)