python迭代协议
1.迭代协议: 可迭代类型 Iterable 迭代器iterator
2.什么是迭代器:
迭代器是用来访问集合内元素的一种方式,一般用来遍历数据
迭代器和下标的访问方式不一样,迭代器是不能返回的,迭代器提供了一种惰性数据的方式
[] list , __ iter __
#from _collections_abc import Iterator,Iterable
from collections.abc import Iterator,Iterable
#list
a=[1,2,3,4]
print(isinstance(a,Iterable)) #True
print(isinstance(a,Iterator)) #False
#如果list实现了iter()并且返回了Iterator1迭代器,
#那么Iterator就是一个迭代器
Iterator1=iter(a)
print(isinstance(Iterator1,Iterator))#True
源码:
Iterable:
class Iterable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is Iterable:
return _check_methods(C, "__iter__")
return NotImplemented
Iterator:
class Iterator(Iterable):
__slots__ = ()
@abstractmethod
def __next__(self):
'Return the next item from the iterator. When exhausted, raise StopIteration'
raise StopIteration
def __iter__(self):
return self
@classmethod
def __subclasshook__(cls, C):
if cls is Iterator:
return _check_methods(C, '__iter__', '__next__')
return NotImplemented
自定义迭代器
下面这段代码是将类的对象变为可迭代对象,然后通过iter(实例化对象)
返回一个迭代器。
class Company(object):
def __init__(self,employee_list):
self.employee=employee_list
'''
如果函数中_iter_和__getitem__都没有实现,
则在使用iterator=iter(类的实例化对象)会报出错误
'''
def __iter__(self):
return iter(self.employee)
# def __getitem__(self, item):
# return self.employee[item]
if __name__=="__main__":
company=Company(["xiaopang","xiaohe","like"])
my_itor=iter(company)
for item in company:
print(item)
自定义迭代器:
class Company(object):
def __init__(self,employee_list):
self.employee=employee_list
'''
如果函数中_iter_和__getitem__都没有实现,
则在使用iterator=iter(类的实例化对象)会报出错误
'''
def __iter__(self):
return MyIterator(self.employee)
from collections.abc import Iterator
class MyIterator: #迭代器是在需要的使用
def __init__(self,employee_list):
self.iter_list=employee_list
#维护内部的一个变量
self.index=0
#__iter__在这个自定义的迭代器中可不用实现
# def __iter__(self):
# return self
def __next__(self):
#真正返回迭代值的逻辑
try:
word=self.iter_list[self.index]
except IndexError:
raise StopIteration
self.index+=1
return word
if __name__=="__main__":
company=Company(["xiaopang","xiaohe","like"])
my_itor=iter(company)
# for item in company:
# print(item)
while True:
try:
print(next(my_itor))
except StopIteration:
pass
pass
生成器函数的使用
#生成器函数 函数里只要存在 yield关键字
def gen_func():
yield 1
#返回的是一个生成器对象,生成器对象是在python
#编译字节码的时候就产生了
yield 2
yield 3
#传统做法
def fib(index):
if index<=2:
return 1
else :
return fib(index-1)+fib(index-2)
print(fib(10))
def fib1(index):
re_list=[]
n,a,b=0,0,1
while n<index:
re_list.append(b)
a,b=b,a+b
n+=1
return re_list
print(fib1(10))
#斐波那契 0 1 2 3 5 8 13 21 34 55
#惰性求值延迟求值提供了可能
#使用生成器实现斐波那契
def gen_fib(index):
n,a,b=0,0,1
while n<index:
yield b
a,b=b,a+b
n+=1
print("...........生成器..........")
for data in gen_fib(10):
print(data)
print(".......................")
def func():
return 1
if __name__=="__main__":
gen=gen_func()
#生成器对象也是实现了我们的迭代器协议的
for value in gen:
print(value)
re=func()
pass
生成器原理
1.python函数运行原理:
#python在运行之前会编译,变异成字节码文件
#python中函数的工作原理
import inspect
frame=None
def foo():
bar()
def bar():
global frame
frame=inspect.currentframe()
# python解释器python.exe使用c语言来写的,解释器会用
#一个叫做PyEval_EvalFramEx() 的c语言函数去执行python
#函数foo,首先会创建一个栈帧(stack frame)
"""
python中一切皆对象,栈帧是一个对象,会将python中的对象
变为字节码对象 当foo调用子函数bar,又会创建一个栈帧,并将
解释器的控制权交给这个栈帧对象,然后将bar变为字节码对象
所有的栈帧都是分配在堆内存上,堆内存如果不去释放它,它
就会一直存放在堆内存当中,这就决定了栈帧可以独立于调用
者存在
"""
# import dis
# #查看函数foo的字节码
# print(dis.dis(foo))
'''
查看foo函数的字节码过程:
6 0 LOAD_GLOBAL 0 (bar)
2 CALL_FUNCTION 0
4 POP_TOP
6 LOAD_CONST 0 (None)
8 RETURN_VALUE
None
'''
foo()
# 这个函数调用完之后我们依然可以拿到它的栈帧
print(frame.f_code.co_name) #bar
#可以拿到调用bar的栈帧
caller_frame=frame.f_back
print(caller_frame.f_code.co_name)#foo
2.生成器
生成器像上述一样运行在堆内存当中,并且独立于调用者存在,完成了对函数整个运行过程的控制。yield生成器对象可以让函数暂停,并访问到f_lasti和f_locals。
def gen_fun():
yield 1
name="xiaopang"
yield 2
age =23
return "eater"
import dis
gen=gen_fun() #生成器运行在堆内存中
print(dis.dis(gen))
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
#
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
'''
53 0 LOAD_CONST 1 (1)
2 YIELD_VALUE
4 POP_TOP
54 6 LOAD_CONST 2 ('xiaopang')
8 STORE_FAST 0 (name)
55 10 LOAD_CONST 3 (2)
12 YIELD_VALUE
14 POP_TOP
56 16 LOAD_CONST 4 (23)
18 STORE_FAST 1 (age)
57 20 LOAD_CONST 5 ('eater')
22 RETURN_VALUE
None
'''
生成器在UserList当中的应用
class company:
def getitem(self, item):
pass
list源码用c语言写的,看不到它的实现,
可以通过from collections import UserList查看python实现
from collections import UserList
from _collections_abc import MutableSequence,Sequence
Sequence源码:
class Sequence(Reversible, Collection):
"""All the operations on a read-only sequence.
Concrete subclasses must override __new__ or __init__,
__getitem__, and __len__.
"""
__slots__ = ()
@abstractmethod
def __getitem__(self, index):
raise IndexError
def __iter__(self):
i = 0
try:
while True:
v = self[i]
yield v
i += 1
except IndexError:
return
def __contains__(self, value):
for v in self:
if v is value or v == value:
return True
return False
def __reversed__(self):
for i in reversed(range(len(self))):
yield self[i]
def index(self, value, start=0, stop=None):
'''S.index(value, [start, [stop]]) -> integer -- return first index of value.
Raises ValueError if the value is not present.
'''
if start is not None and start < 0:
start = max(len(self) + start, 0)
if stop is not None and stop < 0:
stop += len(self)
i = start
while stop is None or i < stop:
try:
v = self[i]
if v is value or v == value:
return i
except IndexError:
break
i += 1
raise ValueError
def count(self, value):
'S.count(value) -> integer -- return number of occurrences of value'
return sum(1 for v in self if v is value or v == value)
Sequence.register(tuple)
Sequence.register(str)
Sequence.register(range)
Sequence.register(memoryview)
使用生成器读取大文件的一个应用
1.准备input.txt
只有1行数据
{|}作为分隔符
文件不大作为测试用。
bfksabcdkbaklbndklsnbklankldnklsnfklsnfsnflns{|}春花秋月{|}The Raspberry Pi Foundation是英国一个小型的慈善组织,成立的宗旨在于推广科技,而非以销售技术来营利。该基金会{|}过去从来没真的发表过一款产品,因而选择了两家全球渠道商e络盟和RS Components为其处理首批Raspberry Pi订单。面对{|}的是业余爱好者和热心DIY 的科技迷,Raspberry Pi销售非常不错。{|}Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的迷你电脑,预装Linux系统,体积仅信用{|}卡大小,搭载ARM架构处理器,运算性能和智能手机相仿{|}在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外还有快速以太网接口、SD卡扩展接口以及1个HDMI高{|}清视频输出接口,可与显示器或者TV相连{|}在查raspberry pi B版针脚定义的时候发现了r-pi短短的一{|}年时间已经经历了4代了,下面就把我搜集的几个版本图片分享给大家,简单说说各个版本的差别{|}最早诞生时,测试版的raspberry pi诞生于英国 伦敦国王大学 King’s College London {|}简称KCL 该学校有完善的电子开发环境,包括自己印制电路板,所以在最初版的raspberry {|}pi在树莓派Logo左侧有该电路板的编号 KCL-8-94V-0 ,板子所用零件都是杂七杂八非生产{|}物料提供,最初版的实物照片只在官方论坛的一些内部用户帖子中出现,市面没有流通{|}正式面世量产的第一版和它非常相向,基本零件规格使用上没有差别,只是插接件{|}贴片元件均使用工厂批量生产的规格,用料好,板子脱去了beta版的青涩,变得成熟性感。{|}正式第一版上市后各大媒体开始疯狂报道,树莓派的队伍也越来越壮大{|}球Geek的摆弄,很早就有了超频的内核出现,直到2012-8-16开始,官方也提供了超频内核,并开放{|}了config.txt用于自定义超频,不过,这是在发布第二版之后才官方开放的。
2.读取的代码:
#读取大文件500G 文件只有一行
# f=open()
# f.readline()和f.readlines()这两个
# 都是直接将所有内容一次性直接放到内存当中的
'''
f.read()很多人认为它是一次性将文件读入到我们的内存当中,实际上
这里面如果我们传递一个参数数字200它就只会读出200个字符,如果我
们接着继续f.read(300),它就会接着我们上一次的偏移量进行读取,这个
偏移量对象内部已经维护好了,我们不需要维护它之前读过的偏移量。
我们只需要反复的多次调用f.read()就可以完成继续读取数据。
'''
# 文件对象 分隔符
def myreadlines(f,newline):
#声明一个缓存 存储已经读出来的数据
buf=""
while True:
'''
这个while循环使用来处理f.read(4096*10)有可能读取数行数据
则会包含多个分隔符,这个while循环不断进行判断是否只有一个
分隔符
'''
#查询 缓存中是否包含了分隔符
while newline in buf:
#找出分隔符在缓存字符串的位置
pos=buf.index(newline)
#使用生成器将已缓存的数据返回
yield buf[:pos]
#取出分隔符后面的数据
buf=buf[pos+len(newline):]
chunk=f.read(4096*10)
#说明已经读到了文件的结尾
if not chunk:
yield buf
break
buf+=chunk
with open("input.txt") as f:
for line in myreadlines(f,"{|}"):
print(line)
"""
打印结果:
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter09/readFile.py
bfksabcdkbaklbndklsnbklankldnklsnfklsnfsnflns
春花秋月
The Raspberry Pi Foundation是英国一个小型的慈善组织,成立的宗旨在于推广科技,而非以销售技术来营利。该基金会
过去从来没真的发表过一款产品,因而选择了两家全球渠道商e络盟和RS Components为其处理首批Raspberry Pi订单。面对
的是业余爱好者和热心DIY 的科技迷,Raspberry Pi销售非常不错。
Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的迷你电脑,预装Linux系统,体积仅信用
卡大小,搭载ARM架构处理器,运算性能和智能手机相仿
在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外还有快速以太网接口、SD卡扩展接口以及1个HDMI高
清视频输出接口,可与显示器或者TV相连
在查raspberry pi B版针脚定义的时候发现了r-pi短短的一
年时间已经经历了4代了,下面就把我搜集的几个版本图片分享给大家,简单说说各个版本的差别
最早诞生时,测试版的raspberry pi诞生于英国 伦敦国王大学 King’s College London
简称KCL 该学校有完善的电子开发环境,包括自己印制电路板,所以在最初版的raspberry
pi在树莓派Logo左侧有该电路板的编号 KCL-8-94V-0 ,板子所用零件都是杂七杂八非生产
物料提供,最初版的实物照片只在官方论坛的一些内部用户帖子中出现,市面没有流通
正式面世量产的第一版和它非常相向,基本零件规格使用上没有差别,只是插接件
贴片元件均使用工厂批量生产的规格,用料好,板子脱去了beta版的青涩,变得成熟性感。
正式第一版上市后各大媒体开始疯狂报道,树莓派的队伍也越来越壮大
球Geek的摆弄,很早就有了超频的内核出现,直到2012-8-16开始,官方也提供了超频内核,并开放
了config.txt用于自定义超频,不过,这是在发布第二版之后才官方开放的。
"""
完结
下一篇 python socket 编程