日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python中的迭代器,生成器,闭包,装饰器,@property

發布時間:2024/9/30 python 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中的迭代器,生成器,闭包,装饰器,@property 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一.迭代器

迭代器在Python中無處不在。它們在for循環,理解,生成器等中優雅地實現,但卻隱藏在眼皮底下。

Python中的Iterator只是一個可以迭代的對象。一個將返回數據的對象,一次返回一個元素。

從技術上講,Python 迭代器對象必須實現兩個特殊方法,iter()和__next__()統稱為迭代器協議。

如果我們可以從對象獲得迭代器,則該對象稱為可迭代。Python中的大多數內置容器(例如:list,tuple,string等)都是可迭代的。

iter()函數(也就是__iter__()方法)從它們返回一個迭代器。

1示例

my_list = [4, 7, 0, 3]# 使用iter()獲得迭代器 my_iter = iter(my_list) #輸出 4 print(next(my_iter)) #輸出 7 print(next(my_iter)) ## next(obj)與obj .__ next __()相同 #輸出 0 print(my_iter.__next__())

2for循環
在正常編碼中,我們常常使用for循環來迭代

for element in iterable:# 對元素做點什么

其真實 for 循環 內部代碼為

# 創建一個迭代器對象iterable iter_obj = iter(iterable)# 無限循環 while True:try:# 獲取下一項element = next(iter_obj)# 對元素做點什么except StopIteration:# 如果引發StopIteration,則從循環中斷break

因此,在內部,for循環通過在iterable上調用iter()創建一個迭代器對象iter_obj。

具有諷刺意味的是,這個for循環實際上是一個無限的while循環。

在循環內部,它調用next()來獲取下一個元素,并使用這個值執行for循環的主體。當所有的項都用完后,StopIteration被拋出,它在內部被捕獲,循環結束。注意,任何其他類型的異常都會通過。

3構建自己的迭代器
在Python中從頭開始構建迭代器很容易。我們只需要實現這些方法__iter__()和__next__()。

iter()方法返回迭代器對象本身。如果需要,可以執行一些初始化。

next()方法必須返回序列中的下一項。在到達終點時,以及在隨后的調用中,它必須引發StopIteration。

這里,我們展示了一個示例,它將在每次迭代中為我們提供2的次冪。冪指數從0到用戶設置的數字。

class PowTwo:"""實現迭代器的類二的冪"""def __init__(self, max = 0):self.max = maxdef __iter__(self):self.n = 0return selfdef __next__(self):if self.n <= self.max:result = 2 ** self.nself.n += 1return resultelse:raise StopIterationa = PowTwo(4) print(a.__iter__()) print(a.__next__()) print(a.__next__()) print(a.__next__()) print(a.__next__()) print(a.__next__()) print(a.__next__())

二.生成器

1什么是生成器
用Python構建迭代器有很多開銷; 我們必須使用__iter__()和__next__()方法實現一個類,跟蹤內部狀態,在沒有要返回的值時觸發StopIteration等等。

這既冗長又違反直覺。生成器在這種情況下可以派上用場。

Python生成器是創建迭代器的簡單方法。我們上面提到的所有開銷都由Python的生成器自動處理。

簡而言之,生成器是一個函數,它返回一個對象(迭代器),我們可以對其進行迭代(一次一個值)。

2如何創建生成器
在Python中創建生成器非常簡單。 就像使用yield語句而不是return語句定義普通函數一樣容易。

如果一個函數包含至少一個yield語句(它可能包含其他yield或return語句),那么它就成為一個生成器函數。yield和return都將從函數返回一些值。

不同之處在于,當return語句完全終止一個函數時,yield語句會暫停該函數保存其所有狀態,然后在后續調用時繼續執行。

3生成器函數和普通函數區別
生成器函數包含一個或多個yield語句。
調用時,它返回一個對象(迭代器),但不會立即開始執行。
像__iter__()和__next__()這樣的方法會自動實現。因此,我們可以使用next()來遍歷項目。
一旦函數產生了結果,函數就會暫停,控制就會轉移給調用者。
局部變量及其狀態在連續調用之間被記住。
最后,當函數終止時,在進一步調用時會自動引發StopIteration。

4代碼

# 一個簡單的生成器函數 def my_gen():n = 1print('這是第一次打印')# 生成器函數包含yield語句yield nn += 1print('這是第二次打印')yield nn += 1print('這是最后一次打印')yield na=my_gen() print(a.__next__()) print(a.__next__()) print(next(a)) print(next(a))

5生成器表達式
使用生成器表達式可以輕松地動態創建簡單的生成器。它使建造生成器變得容易。
與lambda函數創建匿名函數相同,生成器表達式創建匿名生成器函數。
生成器表達式的語法類似于Python中的列表理解語法。但是將方括號替換為圓括號。
列表理解與生成器表達式之間的主要區別在于,雖然列表理解生成整個列表,但生成器表達式一次生成一個項目。
他們有點懶,只在需要時才生成項目。由于這個原因,生成器表達式比等價的列表理解的內存效率要高得多。

# 初始化列表 my_list = [1, 3, 6, 10]# 使用列表理解對每個項目進行平方 # 輸出: [1, 9, 36, 100] print('[x**2 for x in my_list]:',[x**2 for x in my_list])# 同樣的事情可以使用生成器表達式來完成 # 輸出: <generator object <genexpr> at 0x0000000002EBDAF8> a=(x**2 for x in my_list) print('a:',a) print('next(a):',next(a))

三.閉包

1嵌套函數中的非局部變量
在了解閉包是什么之前,我們必須首先了解什么是嵌套函數和非局部變量。
在另一個函數內部定義的函數稱為嵌套函數。嵌套函數可以訪問封閉范圍的變量。
在Python中,默認情況下,這些非本地變量是只讀的,并且我們必須將它們明確聲明為非本地變量(使用nonlocal關鍵字)才能進行修改。
以下是訪問非局部變量的嵌套函數的示例。

def print_msg(msg): # 這是外部封閉函數def printer(): # 這是嵌套函數print(msg)printer()# 我們執行這個函數 # 輸出: Hello print_msg("Hello")

2定義閉包函數

在上面的示例中,如果函數print_msg()的最后一行返回了printer()函數而不是調用它,將會發生什么? 這意味著功能定義如下。

def print_msg(msg): # 這是外部封閉函數def printer(): # 這是嵌套函數print(msg)return printer # 這變了# 現在,讓我們嘗試調用此函數。 # 輸出: Hello another = print_msg("Hello") another()

這很不尋常。
print_msg()函數用字符串調用,"Hello"返回的函數綁定到另一個名稱。在調用時another(),盡管我們已經完成了print_msg()函數的執行,但仍然記得該消息。
這種將一些數據(“Hello”)附加到代碼上的技術在Python中稱為閉包。
即使變量超出范圍或函數本身已從當前命名空間中刪除,也會記住封閉范圍中的這個值。

3閉包的條件
從上面的實例可以看出,在Python中,當嵌套的函數在其封閉的范圍內引用一個值時,我們有一個閉包。
以下幾點總結了在Python中創建閉包必須滿足的條件。

  • 我們必須有一個嵌套函數(函數在函數內部)。
  • 嵌套函數必須引用在封閉函數中定義的值。
  • 封閉函數必須返回嵌套函數。
  • 4何時使用閉包
    那么,閉包有什么用呢?
    閉包可以避免使用全局值,并提供某種形式的數據隱藏。它還可以為該問題提供面向對象的解決方案。
    當在一個類中實現的方法很少(大多數情況下是一個方法)時,閉包可以提供另一種更優雅的解決方案。但是,當屬性和方法的數量變大時,最好實現一個類。
    這是一個簡單的示例,其中閉包可能比定義類和創建對象更可取。

    def make_multiplier_of(n):def multiplier(x):return x * nreturn multiplier# 3的乘數 times3 = make_multiplier_of(3)# 5的乘數 times5 = make_multiplier_of(5)# 輸出: 27 print(times3(9))#此時x=9# 輸出: 15 print(times5(3))#此時x=3# 輸出: 30 print(times5(times3(2)))#times3(2)=6,x=times3(2)

    四.裝飾器

    1.什么是裝飾器
    裝飾器接受一個函數,添加一些功能并返回它。
    Python有一個有趣的功能,稱為裝飾器,可將功能添加到現有代碼中。
    這也稱為元編程,因為程序的一部分試圖在編譯時修改程序的另一部分。

    2學習裝飾器的先決條件
    為了了解裝飾器,我們必須首先了解Python的一些基本知識。
    我們必須接受這樣一個事實,即Python中的所有內容都是對象。我們定義的名稱只是綁定到這些對象的標識符。函數也不例外,它們也是對象(帶有屬性)。可以將各種不同的名稱綁定到同一功能對象。
    這是一個實例。

    def first(msg):print(msg) first("Hello")second = first second("Hello")

    當您運行代碼時,這兩個函數first和second給出相同的輸出。在此,名稱first和second指代相同的功能對象。
    現在情況是不是感覺變復雜了點,可以將函數作為參數傳遞給另一個函數。
    如果您在Python中使用過map,filter和reduce之類的函數,那么您已經知道這一點。
    這種以其他函數為參數的函數也稱為高階函數。這是這種函數的一個實例。

    def inc(x):return x + 1def dec(x):return x - 1def operate(func, x):result = func(x)return result operate(inc,3)#4 operate(dec,3)#2

    此外,一個函數可以返回另一個函數。 即閉包

    def is_called():def is_returned():print("Hello")return is_returnednew = is_called()#輸出 "Hello" new()

    3回到裝飾器
    函數和方法被稱為可調用的,因為它們可以被調用。
    實際上,任何實現特殊方法__call __()的對象都稱為可調用的。 因此,從最基本的意義上講,裝飾器是可調用的,可返回可調用的。
    基本上,裝飾器接受一個函數,添加一些功能并返回它。

    def make_pretty(func):def inner():print("我被裝飾了")func()return innerdef ordinary():print("我是普通的函數")ordinary() print('.....') pretty = make_pretty(ordinary) pretty()

    在上面顯示的示例中,make_pretty()是一個裝飾器。在分配步驟中。

    pretty = make_pretty(ordinary)

    函數ordinary()被修飾,返回的函數被命名為pretty。
    我們可以看到decorator函數在原來的函數中添加了一些新功能。這類似于包裝禮物。裝飾器充當包裝器。被裝飾的物品(里面的禮物)的性質不會改變。但是現在,它看起來很漂亮(自從裝飾之后)。
    通常,我們裝飾一個函數并將其重新分配為

    ordinary = make_pretty(ordinary).

    這是一個常見的構造,因此,Python具有簡化此語法的語法。
    我們可以將@符號與裝飾器函數的名稱一起使用,并將其放置在要裝飾的函數的定義上方。例如,

    def make_pretty(func):def inner():print("我被裝飾了")func()return inner@make_pretty def ordinary():print("我是普通的函數") ordinary()

    相當于

    def ordinary():print("我是普通的函數") ordinary = make_pretty(ordinary)

    4.帶參數的裝飾器
    裝飾器里有很多閉包知識

    def smart_divide(func):def inner(a,b):print("我要做除法",a,"和",b)if b == 0:print("哎呀!不能除")returnreturn func(a,b)return inner@smart_divide def divide(a,b):return a/bprint(divide(2,5))

    通過這種方式,我們可以裝飾帶有參數的函數。
    敏銳的觀察者會注意到,inner()裝飾器內部的嵌套函數的參數與其裝飾的函數的參數相同。考慮到這一點,現在我們可以使通用裝飾器可以使用任意數量的參數。
    在Python中,此魔術是通過完成的function(*args, **kwargs)。這樣,args是位置參數的元組,kwargs而是關鍵字參數的字典。這樣的裝飾器的一個實例是。

    def works_for_all(func):def inner(*args, **kwargs):print("我可以裝飾任何函數")return func(*args, **kwargs)return inner

    5.鏈接裝飾器
    可以在Python中鏈接多個裝飾器。
    這就是說,一個函數可以用不同(或相同)的裝飾器多次裝飾。我們只需將裝飾器放置在所需函數之上。

    def star(func):def inner(*args, **kwargs):print("*" * 30)func(*args, **kwargs)print("*" * 30)return innerdef percent(func):def inner(*args, **kwargs):print("%" * 30)func(*args, **kwargs)print("%" * 30)return inner@star @percent def printer(msg):print(msg) printer("Hello")

    五.@property

    在定義和詳細了解@property是什么之前,讓我們了解為什么首先需要使用它。、
    一個實例開始
    假設您決定創建一個以攝氏度為單位存儲溫度的類。它還將實現一種將溫度轉換為華氏溫度的方法。其中一種方法如下。

    class Celsius:def __init__(self, temperature = 0):self.temperature = temperaturedef to_fahrenheit(self):return (self.temperature * 1.8) + 32 # 創建新對象 man = Celsius() # 設定溫度 man.temperature = 37 # 獲得華氏度 print(man.to_fahrenheit())

    如上所示,每當我們分配或檢索任何對象屬性(如temperature)時,Python都會在對象的__dict__字典中進行搜索。

    man.dict
    {‘temperature’: 37}

    現在,讓我們進一步假設我們的課程在客戶中很受歡迎,并且他們開始在程序中使用它。 他們對對象進行了各種分配。

    有一天,一個值得信賴的客戶來找我們,建議溫度不能低于-273攝氏度(熱力學專業的學生可能會說實際上是-273.15攝氏度),也被稱為絕對零度。他進一步要求我們實現這個值約束。作為一家追求客戶滿意度的公司,我們很高興地聽取了這個建議,并發布了1.01版本(對現有類的升級)。

    1 使用getter和setter
    解決上述約束的一個明顯方法是隱藏屬性temperature(將其設為私有),并定義新的getter和setter接口以對其進行操作。這可以如下進行。

    class Celsius:def __init__(self, temperature = 0):self.set_temperature(temperature)def to_fahrenheit(self):return (self.get_temperature() * 1.8) + 32# new updatedef get_temperature(self):return self._temperaturedef set_temperature(self, value):if value < -273:raise ValueError("-273度是不可能的")self._temperature = value

    我們在上面可以看到get_temperature(),set_temperature()已經定義了新方法,此外,用_temperature替換了temperature。下劃線(_)開頭表示Python中的私有變量。

    c = Celsius(-277)
    Traceback (most recent call last):

    ValueError: Temperature below -273 is not possible

    c = Celsius(37)
    c.get_temperature()
    37
    c.set_temperature(10)
    c.set_temperature(-300)
    Traceback (most recent call last):
    ValueError: Temperature below -273 is not possible

    但這不是一個大問題。上述更新的最大問題在于,所有在程序中實現了上一類的客戶端都必須將其代碼從obj.temperature修改為obj.get_temperature(),并將所有分配(例如obj.temperature = val修改為obj.set_temperature( val))。

    這種重構會給客戶帶來數十萬行代碼的麻煩。

    總而言之,我們的新更新不向后兼容。這是@property發揮作用的地方。

    2@property的力量
    python處理上述問題的方法是使用property。我們可以這樣來實現它。

    class Celsius:def __init__(self, temperature = 0):self.temperature = temperaturedef to_fahrenheit(self):return (self.temperature * 1.8) + 32def get_temperature(self):print("獲得的值")return self._temperaturedef set_temperature(self, value):if value < -273:raise ValueError("零下273度是不可能的")print("設定值")self._temperature = valuetemperature = property(get_temperature,set_temperature) c = Celsius()

    同樣,任何訪問如c.temperature都會自動調用get_temperature()。 這就是屬性的作用。 這里還有一些實例。

    同樣,任何設定.temperature都會自動調用set_temperature()。 這就是屬性的作用。

    任何檢索溫度值的代碼都將自動調用get_temperature()而不是字典(dict)查找。 同樣,任何為溫度分配值的代碼都會自動調用set_temperature()。 這是Python中的一項很酷的功能。
    我們可以在上面看到即使創建對象時也會調用set_temperature()。

    3深入了解property
    在Python中,property()是一個內置函數,用于創建并返回屬性對象。該函數的簽名是

    property(fget=None, fset=None, fdel=None, doc=None)

    其中,fget為獲取屬性值的函數,fset為設置屬性值的函數,fdel為刪除屬性的函數,doc為字符串(如注釋)。從實現中可以看出,這些函數參數是可選的。因此,可以簡單地按照以下方式創建屬性對象。

    屬性對象有三個方法,getter()、setter()和deleter(),用于稍后指定fget、fset和fdel。這意味著

    temperature = property(get_temperature,set_temperature)

    也可以分解為

    創建空屬性
    temperature = property()
    設置 fget
    temperature = temperature.getter(get_temperature)
    #設置 fset
    temperature = temperature.setter(set_temperature)

    熟悉Python中裝飾器的程序員可以認識到上述構造可以實現為裝飾器。

    我們可以更進一步,不定義名稱get_temperature,set_temperature,因為它們是不必要的,并且會影響類命名空間。為此,我們在定義getter和setter函數時重用了名稱temperature。這是可以做到的。

    class Celsius:def __init__(self, temperature = 0):self._temperature = temperaturedef to_fahrenheit(self):return (self.temperature * 1.8) + 32@propertydef temperature(self):print("獲得值")return self._temperature@temperature.setterdef temperature(self, value):if value < -273:raise ValueError("零下273度是不可能的")print("設定值")self._temperature = value


    電氣工程的計算機萌新:余登武。
    寫博文不容易,如果你覺得本文對你有用,請點個贊支持下,謝謝。

    總結

    以上是生活随笔為你收集整理的python中的迭代器,生成器,闭包,装饰器,@property的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。