迭代[1]
什么是迭代
遍历取值的过程叫做迭代。
可迭代对象[2]
可以被for循环遍历取值的对象叫做可迭代对象。包括字符串(str)、列表(list)、元组(tuple)、字典(dict)、集合(set)、range等。
自定义可迭代对象
需要在类里面提供iter方法,然后此类的实例对象就是可迭代对象
from collections import Iterable
class CustomClass(object):
def __iter__(self):
pass
def main():
"""入口函数"""
custom = CustomClass()
# 判断CustomClass类的实例对象是不是可迭代对象
print("CustomClass类的实例对象是不是可迭代对象: ", isinstance(custom, Iterable))
if __name__ == '__main__':
main()
#运行结果:
#CustomClass类的实例对象是不是可迭代对象: True
魔法方法__iter()__ 需要一个返回值,否则对custom 进行遍历 报错
for i in custom:
print(i)
# 运行结果:
# Traceback (most recent call last):
# File "/home/python/Desktop/day/mode1.py", line 22, in <module>
# main()
# File "/home/python/Desktop/day/mode1.py", line 16, in main
# for i in custom:
# TypeError: iter() returned non-iterator of type 'NoneType'
需要一个迭代器对象。
自定义迭代器对象
迭代器类需要提供__iter()__ 和 __next()__
from collections import Iterable
from collections import Iterator
class CustomClass(object):
def __init__(self):
super(CustomClass, self).__init__()
# 提供存储数据的列表
self.my_list = list()
# 添加信息
def append_item(self, item):
self.my_list.append(item)
# 提供可迭代对象方法
def __iter__(self):
# 可迭代对象之所以能够把数据迭代出来是通过迭代器完成的
# 可迭代对象的本质是:通过迭代器把数据依次迭代出来
custom_iterator = CustomIterator(self.my_list)
result = isinstance(custom_iterator, Iterator)
print("custom_iterator是否是迭代器:", result)
return custom_iterator
# 自定义迭代器对象: 在类里面提供__iter__和__next__的方法创建的对象就是迭代器
# 迭代器的作用:记录数据的位置以便获取下一个位置的值
class CustomIterator(object):
def __init__(self, my_list):
self.my_list = my_list
# 下标默认是0
self.current_index = 0
def __iter__(self):
return self
# 获取迭代器中下一个值
def __next__(self):
if self.current_index < len(self.my_list):
result = self.my_list[self.current_index]
self.current_index += 1
return result
else:
# 表示下标越界, 抛出停止迭代的异常
raise StopIteration
def main():
"""入口函数"""
custom = CustomClass()
# 添加数据
custom.append_item(1)
custom.append_item(2)
custom.append_item(3)
# for 循环内部自动捕获了StopIteration 异常
for i in custom:
print(i)
if __name__ == '__main__':
main()
# 运行结果:
# custom_iterator是否是迭代器: True
# 1
# 2
# 3
小结:
- 迭代:一般来说就是使用 for循环,遍历取值的过程
- 可迭代对象:可以被 for循环遍历取值的实例对象,或者类里面提供__iter()__ 方法的类的实例对象
- 迭代器对象:类里面提供 __iter()__ 方法 和 __next()__ 方法的类的实例对象
- 可迭代对象的本质:通过迭代器把数据依次迭代出来
- 迭代器的作用:记录迭代的位置,以便获取下一个位置的数据。
- __iter()__ 方法:调用可迭代对象的 __iter()__ 方法,获取可迭代对象的迭代器
- __next()__ 方法:调用迭代器对象的 __next()__ 方法,获取迭代器中的下一个值。
- for 循环的本质:
- 遍历可迭代对象,通过可迭代对象的 __iter()__ 方法获取迭代器,然后通过迭代器的 __next()__ 方法,获取迭代器中的下一个值。
- 遍历迭代器,直接通过迭代器的 __next()__ 方法,获取迭代器中的下一个值。
- for 循环内部捕获了StopIteration 异常
生成器
什么是生成器
生成器是一类特殊的迭代器,既可以通过 for循环遍历取值,或者通过 next() 取值
生成器的创建
推导式
def main():
"""入口函数"""
# 生成器的方式1,把列表推导式的中括号改成小括号创建的对象就是生成器
generator = (i * 2 for i in range(10))
for value in generator:
print(value)
if __name__ == '__main__':
main()
yieid 关键字
# 创建生成器方式2:在def里面看到有yield关键字那么就表示生成器
def func(num):
current_index = 0
print("--------1")
# 循环判断条件是否成立
while current_index < num:
current_index += 1
print("--------2")
# 代码执行到yield会暂停,然后把结果返回出去, 再次启动生成器会在暂停的位置继续往下执行
yield current_index
print("--------3")
def main():
"""入口函数"""
tmp = func(5)
result = next(tmp)
print(result)
result = next(tmp)
print(result)
if __name__ == '__main__':
main()
# 运行结果
# --------1
# --------2
# 1
# --------3
# --------2
# 2
yieid 与 return
- yieid 会暂停函数的运行,返回当前数据,执行 next方法,函数会从暂停的位置继续向下执行
- return 会打断函数的运行,返回结果,再次运行函数,会从头开始重新执行
- yieid 相同条件多次执行可以返回一组有关联的数据
- return 相同条件多次执行返回同一结果
- yieid 和 return 联用只有python3 支持,并且执行到return 会抛出StopIteration 异常
- 除了next 可以启动生成器,send 也可以,send 启动可以传参,但是send 第一次启动生成器的传参必须为None,否则报错(TypeError: can't send non-None value to a just-started generator)
# 创建生成器方式2:在def里面看到有yield关键字那么就表示生成器
def func(num):
current_index = 0
print("--------1")
# 循环判断条件是否成立
while current_index < num:
current_index += 1
print("--------2")
# 代码执行到yield会暂停,然后把结果返回出去, 再次启动生成器会在暂停的位置继续往下执行
sned_value = yield current_index
print("--------3")
if sned_value > 3:
return
print("sned_value ", sned_value)
def main():
"""入口函数"""
tmp = func(5)
result = tmp.send(None)
print(result)
result = tmp.send(2)
print(result)
if __name__ == '__main__':
main()
# 运行结果
# --------1
# --------2
# 1
# --------3
# sned_value 2
# --------2
# 2
协程
什么是协程
协程又称微线程,用户级线程,是Python 中实现多任务的方式之一。特点:在不开辟线程的基础上完成多任务
简单的协程
在 def 中有一个yieid 关键字,就是协程
import time
# 协程1
def func1():
for i in range(5):
print("func1...")
time.sleep(0.2)
yield
# 协程2
def func2():
for i in range(5):
print("func2...")
time.sleep(0.2)
yield
def main():
"""入口函数"""
f1 = func1()
f2 = func2()
for i in range(5):
next(f1)
next(f2)
if __name__ == '__main__':
main()
# 运行结果
# func1...
# func2...
# func1...
# func2...
# func1...
# func2...
# func1...
# func2...
# func1...
# func2...
协程:在单线程的基础上可以完成多任务,多个任务按照一定顺序交替执行
greenlet 和 gevent
greenlet
# greenlet: greenlet框架封装的是yield,greenlet能够让程序员很直观的查看协程的切换
import time
import greenlet
# 任务1
def work1():
for i in range(5):
print("work1...")
time.sleep(0.2)
# 切换到协程2里面执行对应的任务
g2.switch()
# 任务2
def work2():
for i in range(5):
print("work2...")
time.sleep(0.2)
# 切换到第一个协程执行对应的任务
g1.switch()
if __name__ == '__main__':
# 创建协程指定对应的任务
g1 = greenlet.greenlet(work1)
g2 = greenlet.greenlet(work2)
# 切换到第一个协程执行对应的任务
g1.switch()
gevent
import gevent
import time
from gevent import monkey
# 总结: gevent封装是greenlet,可以根据耗时操作自动完成协程之间的切换执行
# 打补丁,让gevent框架识别耗时操作,比如:time.sleep,网络请求延时
monkey.patch_all()
# 任务1
def work1():
for i in range(10):
print("work1....")
time.sleep(0.2)
# gevent.sleep(0.2)
# 任务1
def work2():
for i in range(10):
print("work2....")
time.sleep(0.2)
# gevent.sleep(0.2)
if __name__ == '__main__':
# 创建协程指定对应的任务
g1 = gevent.spawn(work1)
g2 = gevent.spawn(work2)
# 主线程等待协程执行完成以后程序再退出
g1.join()
g2.join()
进程、线程、协程
- 进程是系统资源分配的基本单位,线程是CPU调度的基本单位,协程是在不开辟线程的基础上完成多任务
- 进程资源开销大,稳定性强,效率很低;线程资源开销较小,稳定性较差,效率一般;协程资源开销小,稳定性依赖于线程,效率较高
- 多进程,多线程可能是并行,但协程在一个线程中,所以是并发
- 协程依赖于线程,线程依赖于进程。
进程就像是一个团队,团队有一些资源,线程是团队的成员,主线程就是team leader,协程就是团队中全栈工程师,哪里需要,去哪里。
到此结 DragonFangQy 2018.5.1
网友评论