Python生成器 百日築基之堵漏

来源:https://www.cnblogs.com/caesar-id/archive/2019/01/24/10316858.html
-Advertisement-
Play Games

生成器 函數體內有yield選項的就是生成器,生成器的本質是迭代器,由於函數結構和生成器結構類似,可以通過調用判斷是函數還是生成器.如下: 生成器的優點就是節省記憶體.Python獲取生成器的二種方式: 通過函數獲取生成器 通過生成器推導式創建生成器 通過函數獲取生成器 從列印內容可以看出是生成器.但 ...


生成器
函數體內有yield選項的就是生成器,生成器的本質是迭代器,由於函數結構和生成器結構類似,可以通過調用判斷是函數還是生成器.如下:

def fun():
    yield "我是生成器"
print(fun())

# 列印內容如下:
<generator object fun at 0x0000000002160ED0> 

生成器的優點就是節省記憶體.
Python獲取生成器的二種方式:

  • 通過函數獲取生成器
  • 通過生成器推導式創建生成器

通過函數獲取生成器

def fun(): 
    print("fun") 
    yield "生成器" 
g = fun() 
print(g)    # 列印函數名查看是否是生成器 

# 列印內容如下:
<generator object fun at 0x0000000000510ED0> 

從列印內容可以看出是生成器.但是發現生成器裡面的內容沒有被列印,那如何列印生成器內容呢?我們可以把生成器理解成迭代器的變異版,所以要列印生成器的內容,與迭代器類似,創建生成器對象後.可以使用生成器.__next__()來列印生成器內容.或者next(),send()等來列印生成器,如下:
使用.__next__()來列印生成器中的內容

def fun(): 
    print("fun") 
    yield "生成器" 
    print("我在生成器的下麵") 
g = fun()       # 創建生成器對象 
print(g)        # 列印生成器對象 
print(g.__next__())    # 列印生成器裡面的內容 

# 列印內容如下:
<generator object fun at 0x0000000002200ED0>
fun 
生成器 

可以發現yield下麵的print語句沒有被列印.到yield停止了

def fun(): 
    print("fun") 
    yield "生成器1" 
    print("我在生成器1下麵") 
    yield "生成器2" 
    print("我在生成器2的下麵") 
g = fun()    # 創建生成器對象 
print(g.__next__()) 
print(g.__next__()) 

# 列印內容如下:
fun 
生成器1 
我在生成器1下麵 
生成器2 

由上面兩個事例可以得出一個總結:就是每next一次就執行一次yield上面的代碼一次,yield下麵的代碼不會被執行,這就是生成器的惰性機制
使用next()列印生成器內容

def fun(): 
    print("fun") 
    yield "生成器" 
    print("我在生成器下麵") 
    yield "生成器2" 
    print("我在生成器2的下麵") 
g = fun() 
print(next(g)) # next(g)列印生成器內容 
print(next(g)) # next(g)列印生成器內容 

# 列印內容如下:
fun 
生成器 
我在生成器下麵 
生成器2 

與.__next__()功能類似
使用send(參數)列印生成器內容:
send方法可以給上一層的yield傳遞一個值,如果上一個yield沒有值的話send的參數將被忽略,如果有值yield的值將被改變成當前的參數,還有需要註意的地方就是如果send(參數)做為第一次迭代,由於上一層沒有yield,所以沒有辦法傳參,會導致出現錯誤,錯誤內容如下:
TypeError: can't send non-None value to a just-started generator
我們將send(None)作為第一次調用即可.然後在第二次調用時可以傳適當的參數.
如下:

def fun(): 
    print("fun") 
    val = yield "生成器" 
    print("我在生成器下麵") 
    print(val) 
    yield "生成器2" 
    print("我在生成器2的下麵") 
    yield "生成器3" 
    print("我在生成器3的下麵") 
g = fun() 
print(g.send(None)) 
print(g.send("send")) 
print(g.send("send2")) 

# 列印內容如下:
fun 
生成器 
我在生成器下麵 
send 
生成器2 
我在生成器2的下麵 
生成器3 

生成器的基礎用法:
使用for迴圈列印生成器對象

def fun(): 
    print("fun") 
    yield "生成器" 
    print("我在生成器下麵") 
    yield "生成器2" 
    print("我在生成器2的下麵") 
    yield "生成器3" 
    print("我在生成器3的下麵") 
g = fun() # 創建生成器對象 
for g_buf in g: # 使用for迴圈列印生成器對象 
    print(g_buf) 

# 列印內容如下
fun
生成器
我在生成器下麵
生成器2
我在生成器2的下麵
生成器3
我在生成器3的下麵

yield可以返回任何數據類型,這裡以列表為事例

def fun(): 
    list_1 = [1,2,3,4,5] 
    yield list_1 # 將整個列表作為返回值傳給生成器對象
g = fun() # 創建生成器對象 
print(g.__next__()) # 列印生成器對象 

# 列印內容如下:
[1, 2, 3, 4, 5] 

如果想要yield從列表中每次返回一個元素使用yield from 列表來實現

def fun(): 
    list_1 = [1,2,3,4,5] 
    yield from list_1 
g = fun() # 創建生成器對象 
print(g.__next__()) # 列印生成器對象內容 

# 列印內容如下:
1 

可以發現只列印了列表中的一個元素.可以使用for迴圈列印所有內容:

def fun(): 
    list_1 = [1,2,3,4,5] 
    yield from list_1 
g = fun() 
for g_buf in g: 
print(g_buf) 

# 列印內容如下:
1 
2 
3 
4 
5 

相當於事項了5次print(g.__next__()) # 列印生成器對象內容


推導式:
列表推導式:
如給list_1列表賦值1-20,常規做法如下:

list_1 = [] 
for num in range(20): 
    list_1.append(num) 
print(list_1) 

# 列印內容如下:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

列表list_1和list_2簡單的推導式如下:

list_1 = [num for num in range(20)] 
list_2 = ["Python: %s" % num for num in range(5)]
print(list_1) 
print(list_2) 

# 列印內容如下:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
['Python: 0', 'Python: 1', 'Python: 2', 'Python: 3', 'Python: 4'] 

列表推導式還可以進行篩選,如下:

list_1 = [num for num in range(20) if num < 5 or num == 15]
print(list_1) 

# 列印內容如下:
[0, 1, 2, 3, 4, 15] 

升級一點,將一個嵌套列表中以"a"開頭和以"h"開頭的元素存放在一個空列表中
基礎寫法如下:

names = [['abc', 'abb', 'zzz'],["hello","world","xiaoming"]] 
list_names = [] 
for name_1 in names: 
    if type(name_1) == list: 
        for name_2 in name_1: 
            if name_2.startswith("a") or name_2.startswith("h"):
                list_names.append(name_2) 
print(list_names) 

# 列印內容如下:
['abc', 'abb', 'hello']         

使用列表推導法

names = [['abc', 'abb', 'zzz'],["hello","world","xiaoming"]] 
list_names = [name_2 for name_1 in names if type(name_1) for name_2 in name_1 if name_2.startswith("a") or\ 
name_2.startswith("h")] 

# 列印內容如下:
['abc', 'abb', 'hello'] 

生成器推導式:
與列表推導式類似,只不過列表是使用[],生成器推導式使用的是()

g_1 = (num for num in range(20)) 
print(g_1) 
print(g_1.__next__()) 
print(g_1.__next__()) 

# 列印內容如下:
<generator object <genexpr> at 0x00000000026A0ED0>
0 
1 

從列印內容和使用__next__()方法可以看出g_1是列表表達式.
可以使用for迴圈列印生成器對象

g_1 = (num for num in range(20)) 
for num in g_1: 
  print(num) 

生成器的篩選與列表推導式用法一樣,只不過是()
如下:過濾1-20內的所有偶數

g_1 = (num for num in range(20) if num % 2 == 0) 

 


升級:與上面列表推導式升級練法類似.

names = [['abc', 'abb', 'zzz'],["hello","world","xiaoming"]] 
list_names = (name_2 for name_1 in names if type(name_1) for name_2 in name_1 if name_2.startswith("a") or\ 
name_2.startswith("h")) # 創建生成器對象 
print(list_names) 
for buf in list_names: 
    print(buf) 

# 列印內容下:
<generator object <genexpr> at 0x0000000002150ED0> 
abc 
abb 
hello

 

生成器表達式和列表推導式的區別:

  • 列表推導式比較耗記憶體,一次性載入.生成器表達式幾乎不占用記憶體.使用的時候才分配和使用記憶體
  • 得到的值不一樣,列表推導式得到的是一個列表.生成器表達式獲取的是一個生成器

字典推導式:

list_1 = ["電視劇","電影"] 
list_2 = ["上海灘","黃飛鴻"] 
dict_1 = {list_1[i]:list_2[i] for i in range(len(list_1))} 
print(dict_1) 

# 列印內容如下:
{'電視劇': '上海灘', '電影': '黃飛鴻'} 

集合推導式:
集合的特點;無序,不重覆 所以集合推導式自帶去重功能

list_1 = [1,2,3,4,2,3,5] 
set_1 = {i for i in list_1} # 集合推導式 
print(set_1) 

# 列印內容如下:
{1, 2, 3, 4, 5}

 

總結:

  • 推導式有列表推導式,生成器推導式,字典推導式,集合推導式
  • 生成器表達式: (結果 for 變量 in 可迭代對象 if 條件篩選)
  • 生成器表達式可以直接獲取到生成器對象,生成器對象具有惰性,每次只能列印一個生成器內容,可以使用for迴圈列印生成器所有的內容.

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第75節:Java中的JSP,EL和JSTL 哭吧看不完的!!! 和`Session 請求轉發和重定向的區別: 1. 地址不一樣 2. 請求次數也不一樣 3. 數據無法傳遞 4.跳轉範圍有限制 5. 效率 請求轉發請求1次,只能對當前項目跳轉,重定向請求2次.重定向是無法傳遞的,重定向對跳轉範圍沒有 ...
  • python介紹 這是我們專門為 小白 量身打造的Python新手教程,具有如下特點: 全視頻,手把手,零起點,項目實例,基於船新的Python 版本 。 Python是一種電腦程式設計語言。你可能已經聽說過很多種流行的編程語言,比如非常難學的C語言,非常流行的Java語言,適合網頁編程的Java ...
  • 原文地址:https://blog.csdn.net/u012811805/article/details/80878848 1 jar啟動分離依賴lib和配置 先前發佈boot項目的時候,改動一點東西,就需要將整個項目重新打包部署,十分不便,故把依賴lib從項目分離出來,每次部署只需要發佈代碼即可 ...
  • 2019-01-24 22:30:32 記錄學習PAT的一些知識,有待更新 註:本文是對Algorithm 演算法筆記 的總結 C++標準庫模板(Standard Template Library,STL) 【vector】 1.單獨定義一個vector vector<typename> name; ...
  • 今天小編為大家準備了4本Python入門書籍,讓大家在python的學習路上少走彎路。 1.Python基礎教程 《Python基礎教程》是經典的Python入門教程書籍,本書層次鮮明,結構嚴謹,特別是在最後幾章中,作者將前面講述的內容應用到項目中,並以模板的形式介紹了項目的開發過程,手把手教授Py ...
  • 遞歸 一個函數在執行過程中一次或多次調用其本身便是遞歸,就像是俄羅斯套娃一樣,一個娃娃里包含另一個娃娃。 遞歸其實是程式設計語言學習過程中很快就會接觸到的東西,但有關遞歸的理解可能還會有一些遺漏,下麵對此方面進行更加深入的理解 遞歸的分類 這裡根據遞歸調用的數量分為線性遞歸、二路遞歸與多重遞歸 線性 ...
  • 背景介紹 JSF(京東服務框架,類似dubbo)預設配置了可伸縮的最大到200的工作線程池,每一個向外提供的服務都在其中運行(這裡我們是服務端),這些服務內部調用外部依賴時(這裡我們是客戶端)一般是同步調用,不單獨限制調用併發量,因為同步調用時會阻塞原服務線程,因此實際上所有外部調用共用了JSF的2 ...
  • 0. 寫在最前面 之前實習天天在寫業務,其中有一個業務是非常的複雜,涉及到了特別多的表。最後測下來,一個介面的時間,竟然要5s多。 當時想寫一個AOP,來計算處理介面花費多長時間,也就是在業務邏輯的前面計算開始的時間,業務邏輯後面計算結束的時間,一相減即可。 但我發覺我竟然忘記怎麼寫了,哎,沒辦法, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...