一、装饰器
1.1 目的
- 在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能
1.2 应用场景
- 想要为函数扩展功能时,可以选择用装饰器
1.3 基本装饰器
基本格式:
def func(arg): def inner(): v = arg() return v return inner # 重点: # 第一步:执行func函数并将下面的函数参数传递,相当于:func(index) # 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index) @func def index(): print(123) return 666 print(index)
总结
- 编写格式:
def 外层函数(参数): def 内层函数(*args,**kwargs) return 参数(*args,**kwargs) return 内层函数
- 应用格式:
@外层函数 def index(): #要装饰的函数 pass index()
# 装饰器的编写 def x(func): def y(): # 前 ret = func() # 后 return ret return y # 装饰器的应用 @x def index(): return 10 # 执行函数,自动触发装饰器了 v = index() print(v)
示例:
def func(arg): def inner(): print('before') v = arg() print('after') return v return inner def index(): print('123') return '666' # 示例一 v1 = index() # 执行index函数,打印123并返回666赋值给v1. # 示例二 v2 = func(index) # v2是inner函数,arg=index函数 index = 666 v3 = v2() # 示例三 v4 = func(index) index = v4 # index ==> inner index() # 示例四 index = func(index) index()
1.4 带参数的装饰器
应用场景:flask框架 / django缓存 / 写装饰器实现被装饰的函数要执行N次
# 第一步:执行 ret = xxx(index) # 第二步:将返回值赋值给 index = ret @xxx def index(): pass # 第一步:执行 v1 = uuu(9) # 第二步:ret = v1(index) # 第三步:index = ret @uuu(9) def index(): pass
区别:
# 普通装饰器 def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner @wrapper def index(): pass # 带参数装饰器 def x(counter): def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @x(9) def index(): pass
练习题
# 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): v = [] for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 v.append(data) return v return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
二、 迭代器
2.1 基本知识
用途:对 某种对象(str/list/tuple/dict/set类创建的对象-可迭代对象)中的元素进行逐一获取
表象:具有
__next__
方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)示例:
- 列表转换成迭代器:
- v1 = iter([11,22,33,44])
v1 = [11,22,33,44].__iter__()
- 迭代器想要获取每个值:反复调用
val = v1.__next__()
v1 = [11,22,33,44] # 列表转换成迭代器 v2 = iter(v1) # 迭代器获取每个值 result1 = v2.__next__() print(result1) result2 = v2.__next__() print(result2) result3 = v2.__next__() print(result3) result4 = v2.__next__() print(result4) result5 = v2.__next__() print(result5) # 报错:Stoplteration 表示已经迭代结束
- 列表转换成迭代器:
for循环:运用了迭代器
v1 = [11,22,33,44] # 1.内部会将v1转换成迭代器 # 2.内部反复执行 迭代器.__next__() # 3.取完不报错 for item in v1: print(item)
2.2 可迭代对象
表象:可以被for循环的对象就可以称为是可迭代对象
如何让一个对象变成可迭代对象?
- 在类中实现
__iter__
方法且返回一个迭代器(生成器)
# 示例一: class Foo: def __iter__(self): return iter([1,2,3,4]) obj = Foo() # 示例二: class Foo: def __iter__(self): yield 1 yield 2 yield 3 obj = Foo()
- 在类中实现
注意:只要能被for循环,就是去看他内部的
__iter__
方法
三、 生成器
3.1 基本知识
可以理解为:函数的变异、特殊的迭代器、特殊的可迭代对象
生成器的作用:
- 生成数据
- 迭代
示例:
# 生成器函数(内部是否包含yield) def func(): print('F1') yield 1 print('F2') yield 2 print('F3') yield 100 print('F4') # 函数内部代码不会执行,返回一个 生成器对象 。 v1 = func() # 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。 for item in v1: print(item)
3.2 关键字
yield
- 用途:判断函数是否是生成器函数
yield from
- 用途:从当前生成器函数跳到其他生成器函数中,执行结束后再回原函数继续执行下面代码
def base(): yield 88 yield 99 def func(): yield 1 yield 2 yield from base() # 跳到base函数 yield 3 result = func() for item in result: print(item) # 1 2 88 99 3
3.3 总结
重点:
- 函数中如果存在yield,那么该函数就是一个生成器函数
- 调用生成器函数会返回一个生成器
- 生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值
建议:
生成器函数中一般不要有return
如果需要终止生成器函数中的循环,可以用return
def func(): count = 1 while True: yield count count += 1 if count == 100: return val = func() for item in val: print(item)
生成器示例:读取大文件内容
def func(): # 分批去读取文件中的内容,将文件的内容返回给调用者。 cursor = 0 while True: f = open('db', 'r', encoding='utf-8') # 通过网络连接上redis # 代指 redis[0:10] f.seek(cursor) data_list =[] for i in range(10): line = f.readline() if not line: return data_list.append(line) cursor = f.tell() f.close() # 关闭与redis的连接 for row in data_list: yield row for item in func(): print(item)