欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解python中的生成器、迭代器、閉包、裝飾器

 更新時(shí)間:2019年08月22日 16:11:59   作者:三國小夢  
這篇文章主要介紹了python中的生成器、迭代器、閉包、裝飾器的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

迭代是訪問集合元素的一種方式。迭代器是一個(gè)可以記住遍歷的位置的對(duì)象。迭代器對(duì)象從集合的第一個(gè)元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會(huì)后退。

1|1可迭代對(duì)象

以直接作用于 for 循環(huán)的數(shù)據(jù)類型有以下幾種:

  • 一類是集合數(shù)據(jù)類型,如 list 、 tuple 、 dict 、 set 、 str 等;
  • 一類是 generator ,包括生成器和帶 yield 的generator function。

這些可以直接作用于 for 循環(huán)的對(duì)象統(tǒng)稱為可迭代對(duì)象: Iterable 。

1|2判斷是否可以迭代

可以使用 isinstance() 判斷一個(gè)對(duì)象是否是 Iterable 對(duì)象:

from collections import Iterable
isinstance([],Iterable)
# True
isinstance({},Iterable)
# True
isinstance(123,Iterable)
# False
isinstance((x for x in range(10)),Iterable)
# True

1|3什么是迭代器

可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)值的對(duì)象稱為迭代器:Iterator。

可以使用 isinstance() 判斷一個(gè)對(duì)象是否是 Iterator 對(duì)象:

from collections import Iterator
isinstance([],Iterator)
False
isinstance({},Iterator)
False
isinstance((x for x in range(10)),Iterator) # 
True

生成器都是迭代器。

1|4iter()函數(shù)

雖然list 、 tuple 、 dict 、 set 、 str 等是可迭代對(duì)象,但他們不是迭代器??梢酝ㄟ^iter()函數(shù)把可迭代對(duì)象編程迭代器。

isinstance(iter([]),Iterator)
# True
isinstance(iter({}),Iterator)
# True
isinstance(iter("asdf"),Iterator)
# True

1|5總結(jié):

  • 凡是可作用于 for 循環(huán)的對(duì)象都是 Iterable 類型。
  • 凡是可作用于 next() 函數(shù)的對(duì)象都是 Iterator 類型。
  • 集合數(shù)據(jù)類型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不過可以通過 iter() 函數(shù)獲得一個(gè) Iterator 對(duì)象。

2|0生成器

2|1什么是生成器

我們可以通過列表生成式來創(chuàng)建一個(gè)列表,但是收到內(nèi)存的限制,列表的容量肯定是有限的。而且,創(chuàng)建一個(gè)包含100萬個(gè)元素的列表,不僅占用很大的存儲(chǔ)空間,如果我們僅僅需要訪問前面幾個(gè)元素,那后面絕大多數(shù)元素占用的空間都白白浪費(fèi)了。所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。在Python中,這種一邊循環(huán)一邊計(jì)算的機(jī)制,稱為生成器:generator。

1|1修改列表推導(dǎo)式創(chuàng)建生成器的方法

最簡單的方法是把列表生成式中的 [ ] 改成 ( ) 就好了。

a = [x for x in range(10)]
print(a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = (x for x in range(10))
print(b) # <generator object <genexpr> at 0x03387DB0>

如何遍歷生成器

我們發(fā)現(xiàn)生成器不是能直接打印出來的,我們可以通過next()函數(shù)來獲得生成器的下一個(gè)返回值。

生成器保存的是算法,每次調(diào)用 next(G) ,就計(jì)算出 G 的下一個(gè)元素的值,直到計(jì)算到最后一個(gè)元素,沒有更多的元素時(shí),拋出 StopIteration 的異常。

**使用next() 或者_(dá)_next __():**
print(next(b))
# 0
print(next(b))
# 1
print(next(b))
# 2
print(next(b))
# 3
print(next(b))
# 4
print(next(b))
# 5
print(b.__next__())
# 6
print(b.__next__())
# 7
print(b.__next__())
# 8
print(b.__next__())
# 9
print(b.__next__())
# Traceback (most recent call last):
# File "<input>", line 2, in <module>
# StopIteration

那么有什么簡單的方法呢?因?yàn)樯善魇强傻鷮?duì)象,也可以使用for循環(huán)來遍歷它,并且不需要關(guān)心 StopIteration 異常。

b = (x for x in range(10))
for x in b:
 print(x)
# 0
# 1
# 2
# 3
#...

1|2函數(shù)中使用yield創(chuàng)建生成器的方法

如果如果生成器推算的算法比較復(fù)雜,用類似列表生成式的 for 循環(huán)無法實(shí)現(xiàn)的時(shí)候,還可以用函數(shù)來實(shí)現(xiàn)。把你要返回的值前面加yield 即可。

使用函數(shù)實(shí)現(xiàn)上面代碼:

def fn():
 for x in range(3):
  yield x
# 遍歷函數(shù)實(shí)現(xiàn)的生成器
f = fn()
print(next(f))
# 0
print(next(f))
# 1
print(next(f))
# 2
print(next(f))
# Traceback (most recent call last):
# File "<input>", line 1, in <module>
# StopIteration

使用生成器實(shí)現(xiàn)斐波拉契數(shù)列:

def fib(count):
 n = 0
 a,b = 0,1
 while n < count:
  yield b
  a,b = b,a+b
  n += 1
 return "done"
f = fib(5)
print(next(f))
# 1
print(next(f))
# 1
print(next(f))
# 2
print(next(f))
# 3
print(next(f))
# 5
print(next(f))
# Traceback (most recent call last):
# File "<input>", line 1, in <module>
# StopIteration: done

yield執(zhí)行流程

  • 當(dāng)執(zhí)行next(f)時(shí),函數(shù)開始執(zhí)行到y(tǒng)ield,yield 右邊的變量x作為next()的返回值被返回,此時(shí)函數(shù)保存當(dāng)前的運(yùn)行狀態(tài),并暫停執(zhí)行。
  • 再次調(diào)用next(f)時(shí),函數(shù)從上次暫停的位置開始繼續(xù)執(zhí)行,再次遇到y(tǒng)ield時(shí)重復(fù)上面的操作
  • 直到生成器遍歷結(jié)束

我們在循環(huán)過程中不斷調(diào)用 yield ,就會(huì)不斷中斷。當(dāng)然要給循環(huán)設(shè)置一個(gè)條件來退出循環(huán),不然就會(huì)產(chǎn)生一個(gè)無限數(shù)列出來。同樣的,把函數(shù)改成generator后,我們基本上從來不會(huì)用 next() 來獲取下一個(gè)返回值,而是直接使用 for 循環(huán)來迭代:

for x in fib(5):
 print(x)
# 1
# 1
# 2
# 3
# 5

但是用for循環(huán)調(diào)用generator時(shí),發(fā)現(xiàn)拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲StopIteration錯(cuò)誤,返回值包含在StopIteration的value中:

f = fib(5)
while True:
 try:
  print(next(f))
 except StopIteration as e:
  print("生成器返回值:%s"%e.value)
  break
# 1
# 1
# 2
# 3
# 5
# 生成器返回值:done

1|3send方法

def gen():
 i = 0
 while i<3:
  temp = yield i
  print(temp)
  i+=1
g = gen()
print(g.__next__())
# 0
print(g.send(None))
# None
# 1
print(next(g))
# None
# 2
print(g.send("哈哈")
# 哈哈
# Traceback (most recent call last):
# File "<input>", line 1, in <module>
# StopIteration

上面代碼可以看出next()、next ()、send(None)是等價(jià)的并沒有什么區(qū)別。

  • send()其實(shí)是比他們更高級(jí)的,在之前的代碼中yield i是沒有返回值的即輸出為None。
  • 如果修改send()的形參,那么yield i 的返回值就是括號(hào)中的形參,在上面的代碼中g(shù).send("哈哈")相當(dāng)于temp = "哈哈",并且g.send("哈哈")的返回值就是變量i。
  • 使用send時(shí)要注意,第一次調(diào)用生成器對(duì)象時(shí),send()不能傳參數(shù)否則會(huì)報(bào)錯(cuò),第一次必須是send(None),或者第一次調(diào)
  • 用next()、next ()也可以。

3|0閉包

3|1什么是閉包

在函數(shù)內(nèi)部再定義一個(gè)函數(shù),并且這個(gè)函數(shù)用到了外邊函數(shù)的變量,那么將這個(gè)函數(shù)以及用到的一些變量稱之為閉包

def test(number):
 def test_in(number_in):
  print("test_in函數(shù) 的number_in=%s"%number_in)
  return number_in+number
 # 返回test_in函數(shù)的引用
 return test_in
ret = test(20)
print(ret(100)) # 相當(dāng)于直接調(diào)用test_in函數(shù),并給它傳值100
# test_in函數(shù) 的number_in=100
# 120
print(ret(200))
# test_in函數(shù) 的number_in=200
# 220


3|2閉包的一個(gè)例子

在數(shù)學(xué)中,一次函數(shù):y=kx+b,在一條確定的直線中,它的k、b是不變的。求y時(shí),根據(jù)確定的k、b、x來求出。

def line_conf(k, b):
 def line(x):
  return k*x + b
 return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
# 6
# 25

如果沒有閉包,我們需要每次創(chuàng)建直線函數(shù)的時(shí)候同時(shí)說明a,b,x。這樣,我們就需要更多的參數(shù)傳遞,也減少了代碼的可移植性。

4|0裝飾器
4|1什么是裝飾器

裝飾器就是對(duì)一個(gè)函數(shù)進(jìn)行裝飾,給這個(gè)函數(shù)增加額外的功能。

def logging(func):
 def wrap():
  print("正在打印日志!")
  func()
 return wrap

@logging # 該裝飾器為函數(shù)增加了打印日志的額外功能,并且之前函數(shù)內(nèi)部代碼不會(huì)改變。

def login():
 print("張三正在登陸。")
login()
# 正在打印日志!
# 張三正在登陸。
4|2兩個(gè)裝飾器
def makeBold(fn1):
 def wrapped():
  print("----1----")
  return "<b>"+fn1()+"</b>"
 return wrapped

def makeItalic(fn2):
 def wrapped():
  print("----2----")
  return "<i>"+fn2()+"</i>"
 return wrapped

@makeBold
@makeItalic
def f1():
 print("----3----")
 return "hello world"

ret = f1() # 此時(shí)f1并不是f1函數(shù),它是makeBold裝飾器返回的wrapped函數(shù)的引用。
print(ret)
"""
輸出結(jié)果:
----1----
----2----
----3----
<b><i>hello world</i></b>
"""

調(diào)用流程:

  1. 把函數(shù)f1的引用傳入裝飾器makeItalic中的變量fn2,此時(shí)fn2指向f1函數(shù)。
  2. 把裝飾器makeItalic中wrapped函數(shù)的引用傳入裝飾器makeBold的變量fn1,此時(shí)fn1指向裝飾器makeItalic中的wrapped函數(shù)。
  3. ret = f1()表是執(zhí)行f1所指向的函數(shù),并返回給ret。

4|3裝飾器帶參數(shù)

一般情況下裝飾器內(nèi)部函數(shù)的參數(shù)都是不定長參數(shù),保證通用性,確保裝飾任何函數(shù)時(shí)都不會(huì)出錯(cuò)。

def logging(func):
 def wrap(*args,**kwargs):
  print("正在打印日志!")
  func(*args,**kwargs)
 return wrap

@logging # 該裝飾器為函數(shù)增加了打印日志的額外功能,并且之前函數(shù)內(nèi)部代碼不會(huì)改變。

def login(name,dic):
 print("%s正在登陸。"%name)
 print(dic)
login("李四",{"sex":"男"})
# 正在打印日志!
# 李四正在登陸。
# {'sex': '男'}
4|4類裝飾器
class Test(object):
 def __init__(self, func):
  print("---初始化---")
  print("func name is %s"%func.__name__)
  self.__func = func
 def __call__(self):
  print("---裝飾器中的功能---")
  self.__func()
@Test
def test():
 print("----test---")
test()
"""

輸出結(jié)果:

---初始化---
func name is test
---裝飾器中的功能---
----test---
"""

說明:

  • 當(dāng)用Test來裝作裝飾器對(duì)test函數(shù)進(jìn)行裝飾的時(shí)候,首先會(huì)創(chuàng)建Test的實(shí)例對(duì)象并且會(huì)把test這個(gè)函數(shù)名當(dāng)做參數(shù)傳遞到__init__方法中即在__init__方法中的func變量指向了test函數(shù)體。
  • test函數(shù)相當(dāng)于指向了用Test創(chuàng)建出來的實(shí)例對(duì)象。
  • 當(dāng)在使用test()進(jìn)行調(diào)用時(shí),就相當(dāng)于讓這個(gè)對(duì)象(),因此會(huì)調(diào)用這個(gè)對(duì)象的__call__方法。
  • 為了能夠在__call__方法中調(diào)用原來test指向的函數(shù)體,所以在__init __方法中就需要一個(gè)實(shí)例屬性來保存這個(gè)函數(shù)體的引用所以才有了self.__func = func這句代碼,從而在調(diào)用__call __方法中能夠調(diào)用到test之前的函數(shù)體。

總結(jié)

以上所述是小編給大家介紹的python中的生成器、迭代器、閉包、裝飾器,希望對(duì)大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!

相關(guān)文章

  • Python requests模塊用法詳解

    Python requests模塊用法詳解

    這篇文章主要介紹了Python requests模塊用法,Python內(nèi)置了requests模塊,該模塊主要用來發(fā)送HTTP請求,requests模塊比urllib模塊更簡潔
    2023-02-02
  • Python已解決NameError: name ‘xxx‘ is not defined

    Python已解決NameError: name ‘xxx‘ is not&nb

    本文主要介紹了Python已解決NameError: name ‘xxx‘ is not defined,解決報(bào)錯(cuò)NameError: name 'xxx' is not defined的關(guān)鍵在于仔細(xì)檢查拼寫、作用域和賦值等問題,感興趣的可以了解一下
    2024-06-06
  • python提取excel一列或多列數(shù)據(jù)另存為新表代碼實(shí)例

    python提取excel一列或多列數(shù)據(jù)另存為新表代碼實(shí)例

    在日常的工作中,其實(shí)就是用鼠標(biāo)進(jìn)行數(shù)據(jù)篩選,然后選擇你想要這一行數(shù)據(jù)進(jìn)行復(fù)制,下面這篇文章主要給大家介紹了關(guān)于python提取excel一列或多列數(shù)據(jù)另存為新表的相關(guān)資料,需要的朋友可以參考下
    2024-06-06
  • Python學(xué)習(xí)之用pygal畫世界地圖實(shí)例

    Python學(xué)習(xí)之用pygal畫世界地圖實(shí)例

    這篇文章主要介紹了Python學(xué)習(xí)之用pygal畫世界地圖實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • 【Python】Python的urllib模塊、urllib2模塊批量進(jìn)行網(wǎng)頁下載文件

    【Python】Python的urllib模塊、urllib2模塊批量進(jìn)行網(wǎng)頁下載文件

    這篇文章主要介紹了Python的urllib模塊、urllib2模塊批量進(jìn)行網(wǎng)頁下載文件,就是一個(gè)簡單的從網(wǎng)頁抓取數(shù)據(jù)、下載文件的小程序,需要的可以了解一下。
    2016-11-11
  • Python獲取時(shí)間戳代碼實(shí)例

    Python獲取時(shí)間戳代碼實(shí)例

    這篇文章主要介紹了Python獲取時(shí)間戳代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • python接口自動(dòng)化測試之接口數(shù)據(jù)依賴的實(shí)現(xiàn)方法

    python接口自動(dòng)化測試之接口數(shù)據(jù)依賴的實(shí)現(xiàn)方法

    這篇文章主要介紹了python接口自動(dòng)化測試之接口數(shù)據(jù)依賴的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • Python?操作Excel-openpyxl模塊用法實(shí)例

    Python?操作Excel-openpyxl模塊用法實(shí)例

    openpyxl 模塊是一個(gè)讀寫 Excel 2010 文檔的 Python 庫,如果要處理更早格式的 Excel 文 檔,需要用到額外的庫,openpyxl 是一個(gè)比較綜合的工具,能夠同時(shí)讀取和修改 Excel 文檔,這篇文章主要介紹了Python?操作Excel-openpyxl模塊使用,需要的朋友可以參考下
    2023-05-05
  • Python學(xué)習(xí)筆記(一)(基礎(chǔ)入門之環(huán)境搭建)

    Python學(xué)習(xí)筆記(一)(基礎(chǔ)入門之環(huán)境搭建)

    本系列為Python學(xué)習(xí)相關(guān)筆記整理所得,IT人,多學(xué)無害,多多探索,激發(fā)學(xué)習(xí)興趣,開拓思維,不求高大上,只求懂點(diǎn)皮毛,作為知識(shí)儲(chǔ)備,不至于落后太遠(yuǎn)。本文主要介紹Python的相關(guān)背景,環(huán)境搭建。
    2014-06-06
  • Flask框架學(xué)習(xí)筆記之路由和反向路由詳解【圖文與實(shí)例】

    Flask框架學(xué)習(xí)筆記之路由和反向路由詳解【圖文與實(shí)例】

    這篇文章主要介紹了Flask框架學(xué)習(xí)筆記之路由和反向路由,結(jié)合圖文與實(shí)例形式詳細(xì)分析了flask框架中路由與反向路由相關(guān)概念、原理、用法與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-08-08

最新評(píng)論