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()])
 

猜你喜欢

转载自www.cnblogs.com/tewu/p/8992423.html