一、迭代器
1). 迭代器概述
- 类比Java中的迭代器,参考迭代器模式https://www.jianshu.com/p/ee999431fb92
- 被迭代对象对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个
Stoplteration异常
,以终止迭代 - 迭代只能向前。
- 可迭代对象:实现了迭代器的对象(调用内部定义一个iter()方法,实现迭代器功能,创造迭代器对象) (类比Java中的接口)
- 字符串、列表、元组、字典、集合、文件对象这些不是可迭代对象,但使用for遍历的时候调用了他们内部的iter方法生成了迭代器。
- 使用转换
str(t),list(),int(),tuple(),dict(),set()
等也使用迭代器
2). 迭代器使用
- 判断一个对象是否可迭代
from collections import Iterable
a = isinstance("", Iterable)
b = isinstance({}, Iterable)
c = isinstance([], Iterable)
d = isinstance((), Iterable)
# True
- 生成迭代器
a = "abc".__iter__()
# 或者
b = iter("abc")
- 判断一个对象是否为一个迭代器
from collections import Iterator
# 调用iter()方法将可迭代对象转换成迭代器
a = isinstance("abc".__iter__(), Iterator)
-
迭代器使用常用方法 (假设t为迭代器)
-
t.__next__()
: 返回下一个迭代元素 -
next(t)
: 同理,返回下一个迭代元素 -
t.send("****")
:配合函数中的yield使用
-
-
for循环的原理
l = [1, 2, 3]
for i in l:
print(i)
# 内部实现如下
iter_test = l.__iter__() # iter_test = iter(l)
print(iter_test)
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__()) # 这里就抛出异常
- 文件句柄中使用迭代器
with open('test.txt', 'r+') as f:
for i in f:
print(i, end="") # end参数表示打印结束为换行符
使用for遍历文件,可以减少不必要的内存空间占有率
- 补充,获取对象的属性
n = "hahadasheng"
b = dir(n)
print(b)
二、生成器
1). 概述
- 生成器(generator object):动态生成下一个元素,按需生产。
- 直接使用
object._next_()
,无需调用__iter__()
方法 - 生成器就是可迭代对象,延迟计算,一次返回一个结果(利于大数据处理)
- 一个生成器只能遍历一次,生成器在产生的时候只是返回生成器地址,当遍历的时候调用
_next_()
方法,位置才发生变化
2). 生成器的一般使用
- 列表生成式:range函数,动态生成数据
for i in range(0, 101):
print(i)
- 函数生成器:生成斐波那契数列
def fib(max):
n, a, b = 0, 0, 1
while n < max: # 计算n次
yield b # 将函数的执行过程冻结在这一步,并且将b的值返回给next(),相当于return
a, b = b, a + b
n += 1
return "done"
# 这时函数并没有执行,而是返回了一个生成器,注意:不需要使用f.__iter()__;
f = fib(15)
for i in f: # f.__next__() 也是可以的
print(i)
- 函数生成器:向函数中传值
-
send
的作用: 唤醒并执行、发送一个信息到生成器内部(默认发送None,可以在函数内部根据传送的信号确定执行状态,比如用if进行判断是否终止) -
next(?)
、?.__next__()
、?.send(?)
:这三个都能唤醒生成器继续工作。
-
def test():
print("run 1")
x = yield 1
print(x)
yield 2
g = test() # 获得生成器
a = g.__next__() # 生成器开始执行 到yield 1并挂起,并将1返回
print(a)
b = g.send("haha") # 将值传递给x;同时获得穿回来的值
print(b)
- 案例:用函数实现range功能
def range2(n):
count = 0
while count < n:
print("func: %s" % count)
print(count)
count += 1
sign = yield count # 返回数据count,中断程序,当外部调用next(),继续执行函数有了yield加括号,
print("---sign",sign) # 就成了一个生成器,如果有并执行到return 在生成器中,代表生成器的终止,直接走到报错
new_range = range2(10) #产生了一个生成器 print(new_range)
new_range.__next__()
new_range.__next__() #next唤醒并继续执行,相当于给生成器发送了一个None
new_range.send("stop")
3). 三元表达式
- 语法
结果 = value1 if 条件成立就返回value1,如果不成立就返回value2 else value2
- 案例
name='晓庆'
res = '女神' if name == '晓庆' else '不是女神'
print(res)
- 生成器-三元表达式:写到列表和元组里面,按需生产
a = [i if i % 2 == 0 else None for i in range(10)]
print(a) # [0, None, 2, None, 4, None, 6, None, 8, None]
4). 列表解析 (直接动态生成列表)
l1 = ['鸡蛋%s' %i for i in range(10)] #二元
# ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
l2 = ['鸡蛋%s' %i for i in range(10) if i > 5 ] #三元 生成一个列表
# ['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
# 没有四元表达式
# l3 = ['鸡蛋%s' %i for i in range(10) if i > 5 else i]
5). map、sum、min、max迭代器
l = [1, 2, 3, 3, 4]
s = map(lambda x: x**x, l)
print(sum(s))
print(sum(i for i in range(1000)))
6). 生成器 + lambda + 函数闭包 + 延迟执行
import copy
def a():
# 闭包延迟, 返回的为4个匿名函数,但是在执行时i都为3
a, b, c, d = [lambda x: copy.copy(i) * x for i in range(4)]
print(a(2), b(2), c(2), d(2)) # 6 6 6 6
# 设定局部变量,匿名函数中的i分别为 0 1 2 3
e, f, g, h = [lambda x, i = i: copy.copy(i) * x for i in range(4)]
print(e(2), f(2), g(2), h(2)) # 0 2 4 6
# 这里返回的也为延迟,i 统统为 3
return [lambda x:copy.copy(i) * x for i in range(4)]
print([m(2) for m in a()])
网友评论