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 編程