Python——對生成器的一點小測試
阿新 • • 發佈:2018-01-26
try memory lose conn most 否則 結果 因此 red """
1、生成器就是對象
2、每次調用next()方法時就返回一個值,直到拋出StopIteration異常
3、如何創建生成器?很簡單,只需寫一個普通的函數並包含yield語句,而不是return語句,因此,python會自動將這個函數標記為生成器
4、yield語句的主要作用是和return語句一樣返回一個值,但最重要也是最需要明白的是,yield語句返回值後,解釋器會保存對棧的引用
它將被用來在下一次調用next()時回復函數的執行
"""
#創建一個生成器
def mygen():
yield 1
yield 2
yield "a"
yield "b"
# print(mygen()) #此刻,打印出來的是一個生成器對象
# g = mygen()
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))
#print(next(g)) #已結到達最後一個數據了,如果還繼續打印則拋出StopIteration異常
#檢查一個函數是否是一個生成器,是的話返回true,不是的話返回false
# import inspect
# ret = inspect.isgeneratorfunction(mygen)
# print(ret)
#查看生成器的當前狀態
"""
有下面幾種狀態:
1、GEN_CREATED:正在等待第一次被執行
2、GEN_RUNNING:當前正在被解析器執行
3、GEN_SUSPENDED:等待被next()調用喚醒
4、GEN_CLOSED:已結結束運行
"""
#測試一下,是如何查看這些狀態的
import inspect
def mygen2():
yield 1
gens = mygen2()
print(inspect.getgeneratorstate(gens)) #第一次查看狀態是,GEN_CREATED(正在等待第一次被執行)
print(next(gens)) #通過next()調用一次
print(inspect.getgeneratorstate(gens)) #此時的狀態是GEN_SUSPENDED(等待被next()調用喚醒)
try:
print(next(gens)) #再next()一次的話,因沒有值了所以引發了一個StopIteration異常
except StopIteration:
pass
print(inspect.getgeneratorstate(gens)) #那麽,它的狀態是GEN_CLOSED(已結結束運行)
#那麽生成器的應用場景是啥?看個例子
"""
在我的ubuntu操作系統環境
root@udesk:~# ulimit -v 131072 #限制運行內存在128M
root@udesk:~# python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = list(range(10000000))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError #內存錯誤
>>>
#用生成器的方式試試
>>> for v in range(10000000):
... if v == 50000:
... print("found ok")
... break
...
found ok
奇怪的是,我左看右看,看著都不像是生成器啊!
原因是:
在python3中,range()函數會返回生成器,也就是說返回的是一個可叠代對象(這點一定要記住)
所以,我只需要第50000個數字,生成器僅僅只會生成50000個數字,而不是像剛才
那麽樣試圖要生成10000000個數字,導致把內存給撐爆了
我在python2環境中測試了下,那麽需要註意的問題有:
>>> xrange(10000000) #python2中xrange是用於返回生成器(也就是說不會馬上生成,用的時候才會即時的生成)
xrange(10000000)
>>> range(10000000) #range獲取生成器(也就是說會馬上生成數字)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
註意了:在python3中去除掉了xrange()函數,僅有range,python3中的range就是返回生成器
簡單總結,用專家說的話就是:
生成器運行通過即時生成的值以極少的內存消耗來應對大規模的數據集和循環處理
任何時候想要操作大規模數據,生成器都可以幫助確保有效地對數據進行處理
"""
#再看一個例子
#一般的寫法
def addlist(alist):
r = []
for i in alist:
r.append(i + 1)
return r
ret = addlist([1,2,3,4,5])
print(ret)
#通過yield的寫法
def yieldlist(alist):
for i in alist:
yield i + 1
ret1 = addlist([1,2,3,4,5])
print(ret1)
#結果都是一樣,那麽數據量小看不出啥效果,要不你搞1000萬條數據你再試試?效果就立馬出來了
#最後關於send和next
"""
send()與next()的區別在於send可以傳遞參數給yield表達式,
這時傳遞的參數會作為yield表達式的值,而yield的參數是返回給調用者的值。
初始調用時必須先next()或send(None),否則會報錯。
"""
#下面看個例子:我想實現生產一些IP地址,並發送給另外一個函數幹活
def jobs():
while True:
ip = yield #yiend接收send發送過來的ip
print("ssh connection:{},Start power off...".format(ip)) #開始幹活
#生產IP地址
def production_ip():
j = jobs()
next(j) #初始調用時必須先next()
for i in range(10):
ip = "192.168.89.{0}".format(i) #生產IP地址
j.send(ip) #將IP地址發生給幹活的函數jobs
production_ip()
Python——對生成器的一點小測試