迭代器:
可迭代对象:要遵守迭代协议,只要有__iter__方法的,就是可迭代对象,可以被for循环
迭代器:要遵守迭代器的协议,有__iter__和__next__方法的就叫迭代器
创建一个迭代器 == 可迭代对象.__iter__()
使用迭代器,就是 == 迭代器.__next__()
lst = [1,2,3] (三个获取的都是1)
l1 = lst.__iter__().__next__()
l2 = lst.__iter__().__next__()
l3 = lst.__iter__().__next__() print(l1),print(l2),print(l3)都是1
那么换一种方式呢?
lst = [1,2,3]
l1 = lst.__iter__() 从一个可迭代对象转化为迭代器
print(l1.__next__())
print(l1.__next__())
print(l1.__next__()) 此时输出的结果为1,2,3,如果继续往下再加__next__(),就会报错
输出可迭代对象的内存地址
print(str.__iter__('你好')) <str_iterator object at 0x0000017BF45116D8>
print(list.__iter__([1,2,3])) <list_iterator object at 0x0000017BF450B3C8>
print(dict.__iter__({'1':2})) <dict_keyiterator object at 0x0000017BF450C4A8>
print(set.__iter__({1,2,3})) <set_iterator object at 0x0000017BF45196C0>
print(tuple.__iter__((1,2,3))) <tuple_iterator object at 0x0000017BF45116D8>
print(range.__iter__(range(1,5))) <range_iterator object at 0x0000017BF4526D70>
生成器定义:
通俗来说,在函数体中存在yield就是生成器,函数名+小括号就产生了生成器,并且只能向下执行
函数体中的yield,就是辨别生成器和函数的依据
生成器的好处就是可以节省空间,一次性完成从上往下执行
那如何产生一个生成器呢?
产生一个生成器:
def foo():
print(123)
yield 4
print(foo()) 结果为,生成器foo的内存地址
print(foo) 函数foo的内存地址
那么按照上面这个生成器来看,怎么样才能实现print(123)?
def foo():
print(123)
yield 456
f = foo()
print(f.__next__()) 这样就实现了print(123),并有返回值456
print(foo.__next__()) 如果把f换成了foo(),就会一直生成新的生成器,会重复打印123,456
yield的作用:
yield也可以有返回值,同时也会记录生成器执行到哪里,不会再继续往下执行
yield可以指定返回值,没有就是None
现在可以来试着捋一捋生成器的执行流程:
def foo(): 1,定义函数
print(123) 5,执行
yield 456 6,返回值456,停止往下执行
print(789)
yield 1111
g = foo() 2,等号右边foo() 3,将foo()赋值给g
print(g.__next__()) 4,g.__next__()
当有大批量的数据时,用for循环就会占大量的空间,那这时不妨用生成器
li = []
def func():
for i in range(300):
print(i)
li.append(i)
func()
print(li)
def func():
for i in range(300):
yield i
g = func()
print(g.__next__()) 随取随用,不会过多的开辟空间
print(next(g)) 和g.__next__()效果一样
yield和next的对应:
一个.__next__()对应一个yield,如果多了,就会报错
def func():
print(1)
yield 2
print(3)
yield 4
yield 5
yield 6
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g)) 最后一个yield下面可以写代码,但是不会执行
send:发送(在外界向生成器传递参数)
send == __next__ + 传值(传给上一个yield停住的地方)
def func():
print(44)
l = yield 5 send,将'哈哈'传递给l,
print(l)
yield 66
g = func() # 生成一个生成器
print(g.__next__())
print(g.send('哈哈')) 输出结果为:44,5,哈哈,66
再来一个
def func():
print(44)
l = yield 5
print(1)
yield 66
g = func()
print(g.send(None)) 输出结果为:44,5
第一次启动生成器的时候不能用send,但是可以用send(None),这时send的传值功能就取消了,只保留next功能
所以,第一次启动生成器的时候, 生成器.__next__() 或者 生成器.send(None)
yield from:
def func():
lst = [1,2,3,4,5]
yield from lst 在这儿实现的就是for循环,for i in lst:print(i)
g = func()
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__()) ps:yield from只能用next
推导式: 推导式只能走一个分支,但三元运算符可以实现多项
先写结果,再写语句,如果有筛选,在语句后面添加条件
列表:
推导式:
print([i for i in range(16)])
展开式:
li = []
def func():
for i in range(16):
li.append(i)
func()
print(li)
列表筛选:
推导式:
print([i for i in range(10) if i % 3 == 0])
展开式:
li = []
def func():
for i in range(10):
if i % 3 == 0:
li.append(i)
func()
print(li)
集合的推导式:
推导式:
dic = {'1':2,'3':4}
print({i for i in dic.items()}) 结果是:({'3':4},{'1':2})或({'1':2}{'3':4})
筛选:
print({i for i in range(66) if i > 16})
集合的推导式和字典很像,但是它只是集合
字典:
推导式1:
lst1 = ['1','2']
lst2 = [2,3]
print({lst1[i]:lst2[i] for i in range(2)}) 输出结果为{'1':2,'2':3}
推导式2:
dic = {'1':2,'3':4}
print({k:v for k,v in dic.items()})
生成器的推导式:
推导式:
l1 = (i for i in range(1000) 条件) print(l1),生成器的地址
for i in range(10):
print(l1.__next__())
展开式:
def func():
for i in range(100):
if i % 3 == 0:
yield i
g = func()
for n in range(10):
print(g.__next__())