python自动化_day4_迭代器生成器内置函数和匿名函数
什么是可迭代的 含有__iter__方法的就是可迭代的:
python 可迭代对象——Iterable
Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,
像常见的list、tuple、dict、set、str都是。如果给一个准确的定义的话,就是只要它
定义了可以返回一个迭代器的iter方法,或者定义了可以支持下标索引的getitem方法,
那么它就是一个可迭代对象。
python 迭代器对象——Iterator
迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,
当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义
了这个方法的都算是迭代器。迭代器一定是可迭代对象,反过来则不一定
成立。用iter()函数可以把list、dict、str等Iterable变成Iterator
什么是迭代器 含有__iter__方法和__next__方法的就是迭代器
Iterable 判断是不是可迭代的。Iterator判断是不是迭代器
1 l = [1,2,3] 2 new_l = iter(l) 3 print(new_l.__next__()) 4 from collections import Iterable,Iterator 5 print(range(1000000)) 6 print(isinstance(range(10000000),Iterable)) 7 print(isinstance(range(10000000),Iterator))
py2 rangge 不管range多少 会生成一个列表用来存储所有的值
py3 range 不管range多少 都不会实际的生成任何一个值
迭代器的优势:
节省内存
取一个值就能进行接下来的计算,而不需要等待所有的值都计算出来才开始接下来的运算--快
迭代器的特性:惰性运算
1 for i in range(100): 2 print(i) 3 f = open() 4 for line in f: 5 print(f)
列表 字典 元组 字符串 集合 rangge 文件句柄 enumerate 所有能for循环的都是可迭代的,都可以使用next
方法变成一个迭代器
生成器 Genareter
自己写的迭代器就是一个生成器
两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
生成器函数
1 def close(num): 2 ret = [] 3 for i in range(num): 4 ret.append('cloth%s'%i) 5 return ret 6 def close_g(num): 7 for i in range(num): 8 yield 'cloth%s' %i #凡是带有yield的函数就是一个生成器函数 9 g = close_g(10000) 10 print(g.__next__()) 11 print(g.__next__()) 12 print(g.__next__()) 13 print(g.__next__()) 14 15 def func1(): 16 print('1111') 17 yield 1 18 print('222222') 19 yield 2 20 yield 3 #记录当前所在的位置,等待下一次next来触发函数的状态 21 yield 4 22 g = func1() 23 print(g.__next__()) 24 print(g.__next__()) 25 for i in g: 26 print(i)
凡是带有yield的函数就是一个生成器函数
生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
想要生成器函数执行,需要用next
s使用生成器监听文件输入的例子
1 def listen_file(): 2 with open('userinfo') as f: 3 while True: 4 line = f.readline() 5 if line.strip(): 6 yield line.strip() 7 time.sleep(0.1) 8 g = listen_file() 9 for line in g: 10 print(line)
send 关键字
1 def func(): 2 print(1111) 3 ret1 = yield 1 4 print(2222,ret1) 5 ret2 = yield 2 6 print(3333,ret2) 7 yield 3 8 9 g = func() 10 ret = g.__next__() 11 print(ret) 12 g1 = g.send('alex') #send 就是在执行next的过程中,生成一个参数,给生成器函数的内部 13 print(g1)
向生成器中传递值,有一个激活的过程,第一次必须用next触发,后边才可以使用send传参
例子
计算移动平均值
月度 的 天平均收入
第一天200元收入,第二天300元,第三天500元
200 250 333.3333
1 def average(): 2 sum_money = 0 3 day = 0 4 avg = 0 5 while True: 6 money = yield avg 7 sum_money += money 8 day += 1 9 avg = sum_money / day 10 g = average() 11 next(g) 12 print(g.send(200)) 13 print(g.send(300))
预激生成器
1 def init(func): 2 def inner(*args,**kwargs): 3 ret = func(*args,**kwargs) 4 next(ret) # 5 return ret 6 return inner 7 @init 8 def average(): 9 sum_money = 0 10 day = 0 11 avg = 0 12 while True: 13 money = yield avg 14 sum_money += money 15 day += 1 16 avg = sum_money / day 17 g = average() 18 next(g) #预激活 19 print(g.send(200)) 20 print(g.send(300)) 21 预激活做成装饰器,可以节省很多时间 叫做预激生成器 22 yield from 23 def generator_func(): 24 for i in range(5): 25 yield i 26 for j in 'hello': 27 yield j 28 29 g = generator_func()
如何从生成器中取值
第一种 使用next取值 随时可以停止,最后一次会报错
print(next(g))
第二种 使用for循环取值 从头到尾遍历一次,不遇到break不停止
for i in g:
print(i)
第三种 list取值或者tuple取值 数据类型的强转 会把所有的数据都加载到内存里,非常的浪费内存
1 print(g) 2 print(list(g)) 3 def generator_func(): 4 for i in range(5): 5 yield i 6 for j in 'hello': 7 yield j 8 yield from range(5) 9 yield from 'hello' 10 g1 = generator_func() 11 g2 = generator_func() 12 for i in g: 13 print(i) 14 print(g1,g2) 15 next(g1) 16 print(next(g1)) 17 print(next(g1))
生成器函数 是我们python程序员实现迭代器的一种手段
主要手段,在函数中 含有yield 有yield就不建议使用return
调用一个生成器函数,不会执行这个函数中的代码,只是会获得一个生成器(迭代器)
只有从生成器中取值的时候,才会执行函数内部的代码,且每获取一个数据才执行得到这个数据的代码
获取数据的方式包括, next send 循环数据类型的强制转换
yield 返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回,可以用yield from
使用send的时候,在生成器创造出来之后需要进行预激活,这一步可以使用装饰器完成
生成器的特点:节省内存 惰性运算
生成器用来解决内存问题和程序功能之间的解耦
列表推导式
new_list=[] for i in range(10): new_list.append(i**2) print(new_list) print([i**2 for i in range(10)]) print([abs(i) for i in [1,2,3,-5,6,20,17]]) l = [1,2,3,41,-5] print([num for num in l if num%2 == 1]) #30以内所有能被3整除的数 print([num for num in range(30) if num%3 == 0]) #30以内所有能被3整除的数的平方 print([num**2 for num in range(30) if num%3 == 0]) #知道嵌套列表中名字含有两个‘e’的所有名字 names = [['Tom','Billy','Jefferson','Arderm','Wesley','Steven','Joe'], ['alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']] print([name for name_list in names for name in name_list if name.count('e') == 2])
生成器表达式
#30以内所有能被3整除的数 l = [num for num in range(30) if num%3 == 0] #列表推倒式 排序的时候使用列表推导式 g = (num for num in range(30) if num%3 == 0) #生成器表达式 庞大数据量的时候使用生成器表达式 print(l) print(g)
林海峰
egg_list = ['jidan%s' %i for i in range(10)] #列表解析多少鸡蛋 laomuji = ('jidan%s' %i for i in range(10)) #生成器表达式 用一个鸡蛋拿一个鸡蛋 print(laomuji) print(laomuji.__next__()) print(egg_list)
面试题
#第一个 def demo(): for i in range(4): yield i g = demo() g1 = (i for i in g) g2 = (i for i in g1) print(list(g1)) print(list(g2)) #第二个 def add(n,i): return n+i def test(): for i in range(4): yield i g=test() for n in [1,10]: g = (add(n,i) for i in g) n = 1 g = (add(n, i) for i in g) 下边的g是上边g的生成器表达式 n永远都是最后的10 n = 10 g = (add(10, i) for i in (add(10, i) for i in [0,1,2,3])) #(add(10, i) for i in [0,1,2,3])=[10,11,12,13] g = (add(10, i) for i in [10,11,12,13]) g = [20,21,22,23] print(list(g)) #第三题 这种问题跟循环前面的数字没关系 只跟最后一个和有多少个有关系。 def add(n,i): return n+i def test(): for i in range(4): yield i g=test() for n in [1,3,10]: g = (add(n,i) for i in g) n = 1 g = (add(n,i) for i in g) n = 3 g = (add(n,i) for i in g) n = 10 g = (add(n,i) for i in (add(n,i) for i in (add(n,i) for i in [0,1,2,3]))) #然后 n = 10 相加 g = (add(n,i) for i in (add(n,i) for i in [10,11,12,13])) g = (add(n,i) for i in [20,21,22,23]) g = [30,31,32,33] print(list(g))
一个生成器只能取一次值
生成器在不找他要值的时候,始终不执行
当他执行的时候,要以执行时候的所有变量值为准
迭代器
什么是可迭代的 含有__iter__方法的就是可迭代的:
python 可迭代对象——Iterable
Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,
像常见的list、tuple、dict、set、str都是。如果给一个准确的定义的话,就是只要它
定义了可以返回一个迭代器的iter方法,或者定义了可以支持下标索引的getitem方法,
那么它就是一个可迭代对象。
python 迭代器对象——Iterator
迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,
当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义
了这个方法的都算是迭代器。迭代器一定是可迭代对象,反过来则不一定
成立。用iter()函数可以把list、dict、str等Iterable变成Iterator
什么是迭代器 含有__iter__方法和__next__方法的就是迭代器
Iterable 判断是不是可迭代的。Iterator判断是不是迭代器
生成器
自己写的迭代器就是一个生成器
生成器函数
凡是带有yield的函数就是一个生成器函数
生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
想要生成器函数执行,需要用next
生成器的预激活过程
预激活做成装饰器,可以节省很多时间 叫做预激生成器
列表推倒式 和 生成器表达式
l = [num for num in range(30) if num%3 == 0] #列表推倒式 排序的时候使用列表推导式
g = (num for num in range(30) if num%3 == 0) #生成器表达式 庞大数据量的时候使用生成器表达式
如何从生成器中取值
第一种 使用next取值 随时可以停止,最后一次会报错
print(next(g))
第二种 使用for循环取值 从头到尾遍历一次,不遇到break不停止
for i in g:
print(i)
第三种 list取值或者tuple取值 数据类型的强转 会把所有的数据都加载到内存里,非常的浪费内存
预激活做成装饰器,可以节省很多时间 叫做预激生成器
内置函数 不def 定义函数可以直接 加()的都是内置函数
print()
input()
len()
open()
tuple()
list()
bool()
set()
id()
str()
abs()
作用域相关 平时不用
locals() #返回本地作用域中的所有名字
globals() #返回全局作用域中的所有名字
enumerate 可以按照索引和
l = [1,23,45]
ret = enumerate(l)
for i in ret:
print(i)
global 变量 关键字 声明函数内部变量对全局生效
nonlocal 变量 关键字 声明函数内部变量对本层以及下边生效
迭代器 生成器相关
range() 是一个可迭代对象 不是迭代器
range(10)
range(1,10,2)
迭代器 .__next__()
next(迭代器)
iter() .__iter__()
其他 dir 查看一个变量拥有的所有方法 不长写在代码里
print(dir([]))
dir([])
callable() 检查一个变量是否可以被调用 后边加() 就是可以被调用的
print(callable(print))
help 帮助
import os 导入模块 __import__()
某个方法属于某个数据类型的变量,就用.调用
如果某个方法不依赖于任何数据类型,就直接调用 只有内置函数和自己定义的函数是可以直接调用的
剩下的所有内容都是属于数据类型的
open
f = open('file')
f.readline()
f.writable() #可不可以写
跟内存相关
id()
hash()
对于相同可hash的数据的hash值再一次程序的执行过程中总是不变得
print(hash(12345))
print(hash('12312332'))
print(hash('12312332'))
print(hash(('1','2')))
print(hash([])) #不可以哈希
输入输出相关
input() #输入一个值才结束
print(self, *args, sep=' ', end='\n', file=None) # 打印 每一次打印会自动换行
print('我们的祖国是花园',end = '') #指定输出的结尾
print('我们的祖国是花园')
print('我们的祖国是花园')
print('我们的祖国是花园')
print(1,2,3,4,5,sep = '|') #sep 指定输出分割符
指定一个文件 把文件写入一个文件名为f的文件里
f = open('file','w')
print('a',file=f)
f.close()
打印进度条
1 import time 2 for i in range(0,101,2): #0,2,4,6,8 3 time.sleep(0.1) 4 char_num = i//2 #打印多少个'*' 4 5 if i == 100: 6 per_str = '\r%s%% : %s\n' % (i, '*' * char_num) #\r 回到行首 7 else: 8 per_str = '\r%s%% : %s\n'%(i,'*'*char_num) 9 print(per_str,end='',flush=True) # 0.01
exec eval 都可以执行字符串的看起来是python语句的
1 exec('print(123)') 2 eval('print(123)') 3 print(1+2+3+4) 4 print(exec('1+2+3+4')) 5 print(eval('1+2+3+4'))
两个都可以执行字符串类型的代码 eval有返回值简单的计算,exec没有返回值简单的流程控制
eva 只能用在你明确知道你要执行的代码是什么
1 code = '''for i in range(10): 2 print(i*'*') 3 ''' 4 exec(code)
compile() 将字符串进行编译变成字节码 然后用exec 和eval执行
复数 ---- complex
实数 ---- 有理数:整数 有限循环小数 无限循环小数 和 无理数:π
虚数 ---- 虚无缥缈的数
5 + 12j == 复合的数 == 复数 复数之间不能比较大写
和数字相关 只在数据类型转换的时候才用
float 浮点数(有限循环小数 和 无限循环小数) !== 小数:有限循环小数 和 无限循环小数 无线不循环小数
浮点数
354.123 = 3.54123*10**2 = 35.4123*10
f = 1.43287432846824235244645645646
print(f)
进制转换
bin() 二进制
oct() 八进制
hex() 十六进制
0b 二进制
0o 八进制
0x 十六进制
数学运算
print(abs(-7)) 绝对值
divmod() 接收两个参数 求商取余 div 是除法 mod 是取余
print(divmod(10,2))
print(round(3.12312,2)) #做精确值 会四舍五入
print(pow(2,3)) #pow 幂运算2的3次方
print(pow(1,23,4)) # 1的23次幂取余4
sum min max
sum 求和必须是可迭代的 必须是数字
print(sum(range(10)))
print(sum([1,3,4,5,6],10))
min(iterable, *[, default=obj, key=func]) -> value
min(arg1, arg2, *args, *[, key=func]) -> value
print(min([1,23,4,5,]))
print(min(1,23,4,-4))
print(min([111,-23,4,5],key=abs),) #可以添加参数key 以绝对值的求最小值
max(*args, key=None) #可以添加参数key 以绝对值的求最小值
##数据类型有多少:int str list tuple set dict bool。。。。。
##数据结构有多少:容器数据类型list tuple set dict str
##重要的内置函数 reverse
l = [1,23,4]
l.reverse() #翻转
print(l)
l = [1,2,34,5,6]
l2 = reversed(l) #反转之后成生一个迭代器 不改变原来的列表 保留原来的列表生成一个反序迭代器
print(list(l2))
slice
l = (1,2,3,421,321,3,2131,321)
sli = slice(1,5,2)
print(l[sli])
format 如果以后对数学相关可以使用format
print(format('test','<20'))
print(format('test','>20'))
print(format('test','^20'))
###bytes 转换成bytes类型
我拿到的是gbk编码,想转换成utf-8类型 需要先转换成Unicode类型在转换成bytes的utf-8
bytearray byte类型的数组
print(bytearray('ninhao',encoding='utf-8'))
l = '2132134214sdasasdsadsa'
memoryview 切片内存
ord() #字符串转换成数字
chr() #数字转换成字符串
ascii()
print(repr('1'),repr(1)) #可以原封不动的打印出来
name = 'egg'
print('nihao%r' %name)
dict set
frozenset #集合不可变
最重要的几个 len enumerate zip filter map sorted
all 可迭代的 如果里面有一个FALSE就是FALSE
any 可迭代的 有一个True就是True
zip #拉链 可迭代的 把两个拉到一起组成新的展示 按照最短的
l = [1,2,3]
l2 = ['a','b','c']
l3 = (1,3,4)
l4 = {'k':1,'v':2}
for i in zip(l,l2,l3,l4):
print(i)
filter() 跟生成器表达式,列表推导式类似 必须跟函数的名字一起使用 用于筛选
1 def is_odd(x): 2 return x and str(x).strip() 3 ret = filter(is_odd, ['',None,' ',1,2,3,4,7,9]) #filter 生成一个迭代器 节省内存 4 for i in ret: 5 print(i) 6 print([i for i in [1,2,3,4,7,9] if i % 2 == 1]) 7 from math import sqrt 8 def m(x): 9 return sqrt(x) % 1 == 0 10 ret = filter(m,range(100)) 11 print(list(ret)) 12 for i in ret: 13 print(i)
map()
1 ret = map(abs,[1,-4,5,19]) 2 print(ret) 3 for i in ret: 4 print(i)
filter 执行了filter之后的结果集合一定是<= 执行之前的个数
filter 只管筛选,不会改变原来的值
map 元素执行前后个数不变,值可能改变了
sorted 排序 是可迭代的 可以根据要求排序
l = [1,3,4,-5,-7]
l.sort(key=abs) #sort 在愿列表的基础上进行排序
print(l)
l1 = sorted(l,key=abs) #生成一个全新的列表 排序必须读取所有的数据才可以排序,消耗内存
print(l1)
练习
l = [' ',[1,2],'hello','wordle']
l1 = sorted(l,key=len)
print(l1)
匿名函数 lambda
1 cale = lambda n:n**n 2 print(cale(10)) 3 add = lambda a,b:a+b 4 print(add(1,2)) 5 dic = {'k1':1,'k2':3,'k3':1} 6 print(dic[max(dic,key=lambda k:dic[k])]) 7 8 res = filter(lambda x:x>10,[5,8,11,9,15]) 9 print(list(res))
带key的内置函数:max mix filter map sorted 都可以跟key参数使用 或者说都可以跟lanbda合作
1 d = lambda p:p*2 2 t = lambda p:p*3 3 x = 2 4 x = d(x) # x = 4 5 x = t(x) # x = 12 6 x = d(x) 7 print(x)
现有两元组(('a'),('b')),(('c'),('d')),请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]
匿名函数 == 内置函数和匿名函数组合 max min map filter sorted
1 ret = zip((('a'),('b')),(('c'),('d'))) 2 ('a', 'c') ('b', 'd') 3 def func(tup): 4 return {tup[0]:tup[1]} 5 res = map(lambda tup:{tup[0]:tup[1]},ret) 6 print(list(res))
3.以下代码的输出是什么?请给出答案并解释。
1 def multipliers(): 2 return [lambda x:i*x for i in range(4)] 3 print([m(2) for m in multipliers()])