python基礎之迭代器與lamba表達式

迭代

每一次對過程的重複稱爲一次“迭代”,而每一次迭代得到的結果會作爲下一次迭代的初始值。例如:循環獲取容器中的元素。

可迭代對象iterable

具有__iter__函數的對象,可以返回迭代器對象。
對list、tuple、dict、set、str等類型的數據可以通過for…in…這類語句迭代讀取一條數據供我們使用的對象稱之爲可迭代對象(Iterable)。

 class 可迭代對象名稱:
   def __iter__(self):
       return 迭代器

簡單總結:

迭代器 = 可迭代對象.iter()
可以被next()函數調用並返回下一個值的對象

迭代器對象iterator

可以被next()函數調用並返回下一個值的對象。
實現了__next__()魔法方法(類實例化),該方法返回迭代器下一個值(保存得到下一個迭代值的算法)

class 迭代器類名:
	def __init__(self, 聚合對象):
		self.聚合對象= 聚合對象  

	def __next__(self):  
		if 沒有元素:
		raise StopIteration
		return 聚合對象元素

理解可迭代對象iterable 與迭代器對象iterator

可迭代對象包含迭代器。
如果一個對象擁有__iter__方法,其是可迭代對象;如果一個對象擁有__next__方法,其是迭代器。
定義可迭代對象,必須實現__iter__方法;定義迭代器,必須實現__iter__和__next__方法。

使用__iter__與__next__實現迭代(不使用for):

# 定義list類型的可迭代對象
my_list = [1, 2, 3, 7, 8, 9]

# 獲取迭代器
# iterator = my_list.__iter__() # 直接寫法

# iter()函數實際上就是調用了可迭代對象的__iter__方法
iterator = iter(my_list)

# 循環獲取下一個元素
while True:
    try:
        # item = iterator.__next__() 直接寫法
        item = next(iterator) # 與iter() 同理
        print(item)
    # 異常處理
    except StopIteration:  # 迭代完成
        break

使用函數定義__iter__與__next__實現迭代:

class MyIterator:

    def __init__(self, target):
        self.target = target
      	# 下標計數器
        self.index = 0

    def __next__(self):
    	# 如果 下標計數器 > 可迭代對象長度
        if self.index > len(self.target) - 1:
        	# 報錯 
            raise StopIteration()
		
        result = self.target[self.index]
        self.index += 1
        return result

class MyManager:
    """
      可迭代對象
    """

    def __init__(self):
        # 定義一個函數私有變量__list 類型爲list
        self.__list = []

    def add_obj(self, obj):
        self.__list.append(obj)

    def __iter__(self):
        # 返回MyIterator類 實例化對象
        return MyIterator(self.__list)


class Test:
    def __str__(self):
        return "這是Test類"


# 實例化MyManager類
manager = MyManager()

manager.add_obj(Test())
manager.add_obj(Test())
manager.add_obj(Test())

iterator = manager.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

生成器generator

能夠動態(循環一次計算一次返回一次)提供數據的可迭代對象。

作用:在循環過程中,按照某種算法推算數據,不必創建容器存儲完整的結果,從而節省內存空間。數據量越大,優勢越明顯。在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator

ps: 當數據量足夠大時,內存是完全不夠用的,但是又需要迭代計算時,需要惰性操作 : 執行一次,計算一次,而不是創建容器,來存儲整個對象

生成器函數

含有yield語句的函數,返回值爲生成器對象。
yield翻譯爲”產生”或”生成”
調用生成器函數將返回一個生成器對象,不執行函數體。

# 創建生成器函數
def 函數名A():yield 數據

# 使用生成器函數
for i in 函數名A():
	語句

舉例來說:

def Test():
    print('Test1')
    yield 'Test - Test1'
    print('Test2')
    yield 'Test - Test2'
    print('Test3')
    yield 'Test - Test3'

t = Test()
result = next(t)
print(result)

result = next(t)
print(result)

result = next(t)
print(result)

result = next(t) # 第四次調用 超出迭代範圍
print(result)
Test1
Test - Test1
Test2
Test - Test2
Test3
Test - Test3
Traceback (most recent call last):
  File "my_test_2.py", line 19, in <module>
    result = next(t)
StopIteration

執行過程:

Setp1 - 調用生成器函數會自動創建迭代器對象。
Setp2 - 調用迭代器對象的__next__()方法時才執行生成器函數。
Setp3 - 每次執行到yield語句時返回數據,暫時離開。
Setp4 - 待下次調用__next__()方法時繼續從離開處繼續執行。

優點: 不會將所有結果計算出來,存儲在內存中
缺點: 無法通過索引,切片靈活的訪問結果

  • 延遲操作轉爲立即操作 list() 函數從而克服缺點

注意:

生成器只可for遍歷一次,第二次遍歷無效,需要重新調用生成器函數產生生成器

def test(l : list):
    for i in l:
        yield i

if __name__ == '__main__':
    result = test([1, 2, 3])
    for i in result:
        print(i)

    for i in result:
        print(i)

# 結果 只調用一次:
1
2
3

使用 yeild 改寫MyManager 實現惰性操作

# class MyIterator:  全部註釋掉
# 
#     def __init__(self, target):
#         self.target = target
#         # 下標計數器
#         self.index = 0
# 
#     def __next__(self):
#         # 如果 下標計數器 > 可迭代對象長度
#         if self.index > len(self.target) - 1:
#             # 報錯 
#             raise StopIteration()
# 
#         result = self.target[self.index]
#         self.index += 1
#         return result

class MyManager:
    """
      可迭代對象
    """

    def __init__(self):
        # 定義一個函數私有變量__list 類型爲list
        self.__list = []

    def add_obj(self, obj):
        self.__list.append(obj)

    def __iter__(self):
        # return MyIterator(self.__list)
        for item in self.__list:
        	# 將函數變爲 生成器函數
            yield item

class Test:
    def __str__(self):
        return "這是Test類"


# 實例化MyManager類
manager = MyManager()

manager.add_obj(Test())
manager.add_obj(Test())
manager.add_obj(Test())

iterator = manager.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

lambda表達式

通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用,也就是指匿名函數。

作用:作爲參數傳遞時語法簡潔,優雅,代碼可讀性強。

定義方法:
變量 = lambda 形參: 方法體

– 形參沒有可以不填
– 方法體只能有一條語句,且不支持賦值語句。

# 普通函數
def condition1(item):
    return item // 2

# lambda 匿名函數
num = lambda target: target // 2

if __name__ == '__main__':
    print(condition1(100))  # 50
    print(num(100))  # 50

相對普通方法的優缺點:
優點:

省略方法名
減少程序間依賴性
將方法作爲參數,特別優雅

缺點:

由於沒有名字,代碼不能複用
方法體只能一條語句 錯誤方法: a = lambda item:print(“ok”) ; item % 2 == 0
方法體必須有返回值

Python之禪中有這麼一句話:Explicit is better than implicit(明瞭勝於晦澀),就是說那種方式更清晰就用哪一種方式,不要盲目的都使用lambda表達式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章