一.上周回顾复习·
函数:
1.函数名的本质 —— 就是一个变量 里面存储了函数的内存地址 函数名可以作为函数的参数、返回值。可以被赋值,可以作为可变数据类型的元素
2.函数的定义
~参数——形参:
位置参数
*args
默认参数
**kwargs
~返回值 return
返回值为None
返回一个值,这个值可以是任意数据类型
返回多个值,多个值之间用逗号隔开,以元组的形式返回
3.函数调用
~参数——实参:
按照位置传参
按照关键字传参
~获取返回值
接收返回值
不接受返回值
4.函数的应用 ——闭包函数
在内部函数中使用了外部函数的变量,这个内部函数就叫做闭包
5.作用域——全局作用域,局部作用域
全局作用域内的变量可以被局部作用域使用
a = 1 def func(): print(a) func() 输出结果 1
在局部作用域内定义的变量不能在全局作用域使用
def func_b(): b = 20 #b是局部作用域中的变量 func_b() print(b) #报错:在全局作用域中不能使用局部作用域的变量
关于global关键字:
c = 10 def func_c1(): c = 20 print('in func_c1',c) func_c1() print(c) 输出结果 in func_c1 20 10
加入global关键字以后:
c = 10 def func_c2(): global c c = 20 print('in func_c2',c) func_c2() print(c) 输出结果 in func_c2 20 20
~命名空间:内置、全局、局部
6.装饰器 —— 函数的应用
#def wrapper(func):
# def inner(*args,**kwargs):
# '''在执行被装饰的函数之前要做的事情'''
# ret = func(*args,**kwargs)
# '''在执行被装饰的函数之后要做的事情'''
# return ret
# return inner (必背!)
@wrapper
def func():
pass @wrapper 语法糖表示 func = wrapper(func)
二.迭代器
1.迭代器 就是实现了能从其中一个一个的取出值来
~只要包含了“双下iter”方法的数据类型就是可迭代的 —— 可迭代协议
数据类型和python解释器定下来的协议
~'__iter__' 这个方法导致了一个数据类型的可迭代
~迭代器中有 __next__ 和 __iter__方法 —— 迭代器协议
~在python里 你学过的所有的可以被for循环的 基本数据类型 都是可迭代的 而不是迭代器
lst_iterator = [1,2,3].__iter__() print(set(dir(lst_iterator)) - set(dir([1,2,3]))) 输出结果 {'__length_hint__', '__setstate__', '__next__'}
2. 可迭代对象
~可迭代协议:含有__iter__方法的对象
~迭代器协议:含有__iter__和__next__方法的对象
3.迭代器和可迭代对象之间的关系
~可迭代对象包含迭代器
那么可迭代对象是如何成为迭代器的?
迭代器 = 可迭代对象.__iter__()
**可迭代对象并不能用,它是变成迭代器以后才能用的
怎么用呢?
lst_iterator = [1,2,3].__iter__() print(lst_iterator.__next__()) print(lst_iterator.__next__()) print(lst_iterator.__next__()) #迭代器中[1,2,3]打印三个没有了再打印就会报错 输出结果 1 2 3
~for 可以是一个可迭代对象 也可以是一个迭代器
如果 for循环的内容是一个可迭代的对象时,它就会自动的去调用可迭代对象的__iter__方法获取到一个迭代器
~为什么要有迭代器 迭代器存在的本质是什么:
1.能够对python中的基本数据类型进行统一的遍历,不需要关心每一个值分别是什么
2.它可以节省内存 —— 惰性运算
f = open('file','w') 文件句柄就是一个迭代器
range(10000000).__iter__() range就是一个可迭代的对象
~迭代器:
1.天生的,比如文件句柄
2.后天的,可迭代对象.__iter__()
三. 生成器 Iterator 迭代器 Gerator 生成器
1.生成器就是迭代器,生成器是我们自己写出来的
2.生成器分类
~生成器函数:生成器函数可以通过常规的def语句定义,不同的是,不是使用return返回,而是用yield一次返回一个结果,在每个结果之间挂起和继承它们的状态,来自动实现迭代协议。
~生成器表达式:类似于列表推导,但,生成器返回按需生产结果的一个对象,而不是一次构建一个结果列表。
3.什么时候用到生成器??
当创建列表只是一共中间过程的时候,为了避免创建庞大的列表,我们可以使用生成器表达式来完成
- 生成器是可迭代对象;
- 实现了延迟计算,省内存(按需执行);
- 生成器本质和其他类型一样,都是实现了迭代器协议,只不过生成器是一边计算,一边生成,从而节省内存空间,其余的可迭代对象可没有这个功能。
def generator_func(): #生成器函数 print(123) yield 'aaa' #return print(456) yield 'bbb' g = generator_func() #generator生成器 - 生成器的本质就是迭代器 ret = g.__next__() print(ret) ret2 = g.__next__() print(ret2) g = generator_func() print(list(g)) 输出结果 123 aaa 456 bbb 123 456 ['aaa', 'bbb']
**带yield关键字的函数就是生成器函数
**生成器函数在执行的时候只返回一个生成器,不执行生成器函数中的内容
**从生成器中取值:
1.__next__ 有几个yield就可以取几次
2.for循环取值 正常取 for i in g:
3.其他数据类型进行强制转换 list(g) 返回一个列表,里面装着生成器中的所有内容
注意:调用生成器函数的时候,要先获取生成器,再进行next取值
生成器中的内容只能取一次,且按顺序取值没有回头路,取完为止。
def generator(): yield yield 2 g = generator() for i in g: print(i) 输出结果 none 2
进阶示例
def get_clothing(): for cloth in range(1,2000000): yield '第%s件衣服'%cloth g = get_clothing() print(g.__next__()) for i in range(20): print(g.__next__()) 输出结果 第1件衣服 第2件衣服 第3件衣服 第4件衣服 第5件衣服 第6件衣服 第7件衣服 第8件衣服 第9件衣服 第10件衣服 第11件衣服 第12件衣服 第13件衣服 第14件衣服 第15件衣服 第16件衣服 第17件衣服 第18件衣服 第19件衣服 第20件衣服 第21件衣服
import time def tail(filename): f = open(filename,encoding='utf-8') f.seek(0,2) #将文件的光标移到最后 while True: line = f.readline() if not line: time.sleep(0.1) continue yield line tail_g = tail('demo') for line in tail_g: print(line,end='')
四.最后的总结:
1.可迭代对象 内部有__iter__
2.迭代器 内部有__iter__ __next__
3.生成器 就是迭代器
自己写的迭代器
生成器函数 yield /yield from
生成器表达式
def generator_func(): #生成器函数
print(123)
yield 'aaa' #return
print(456)
yield 'bbb'