網站首頁 編程語言 正文
推導式
什么是推導式
推導式是 for 循環的簡化使用方法,使用推導式,將一個可迭代對象中的數據遍歷到某一個容器當中。簡單的來說就是用一行for循環語句,遍歷一個可迭代對象中的所有數據,然后將遍歷出來的數據進行處理放入對應的容器中的一個過程和方式。
和推導類似作用的還有三元運算符,三元運算符是條件判斷語句的簡化使用方法。
語法:
val for val in Iterable
就是存入容器中的數據
+?for循環語句
推導式有三種表達方式,分別用對應的符號包裹推導式語句:
- 列表推導試:[val for val in Iterable]
- 集合推導式:{val for val in Iterable}
- 字典推導式:{x,y for x,y in Iterable}
列表推導式:
列表推到式,遍歷出來的數據最終就會變成一個列表數據。
基本語法
列表中存入10條數據:
# 常規寫法 lst = [] for i in range(1, 11): lst.append(i) print(lst) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 推導式寫法 lst = [i for i in range(1, 11)] print(lst) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
其它使用方法
單循環推導式:
# 處理容器中的數據:[1, 2, 3, 4, 5] -> [3, 6, 9, 12, 15] lst = [1, 2, 3, 4, 5] # 普通寫法 new_lst = [] for i in lst: res = i * 3 new_lst.append(res) print(new_lst) # [3, 6, 9, 12, 15] # 推導式寫法 new_lst = [i * 3 for i in lst] print(new_lst) # [3, 6, 9, 12, 15]
帶有判斷條件的單循環推導式:
# 過濾出奇數 lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 普通寫法 new_lst = [] for i in lst: if i % 2 == 1: new_lst.append(i) print(new_lst) # [1, 3, 5, 7, 9] # 推導式寫法 # 推導式使用單項分支只能是在for語句結束之后使用 new_lst = [i for i in lst if i % 2 == 1] print(new_lst) # [1, 3, 5, 7, 9]
多循環推導式:
# 兩個列表中的數據相加求和 lst = [1, 2, 3] lst1 = [11, 22, 33] # 普通方法 new_lst = [] for i in lst: for j in lst1: res = i + j new_lst.append(res) print(new_lst) # [12, 23, 34, 13, 24, 35, 14, 25, 36] # 推導式寫法 new_lst = [i + j for i in lst for j in lst1] print(new_lst) # [12, 23, 34, 13, 24, 35, 14, 25, 36]
列表推導式練習題
- 1、將字典中的數據變成['x=A', 'y=B', 'z=c']的樣式{'x': 'A', 'y': 'B', 'z': 'C' }
- 2、將所用元素變成純小寫["ADDD","dddDD","DDaa","sss"]
- 3、x是0-5之間的偶數,y是0-5之間的奇數 把x,y組成一起變成元組,放到列表當中
- 4、使用列表推導式 制作所有99乘法表中的運算
- 5、求M,N中矩陣和元素的乘積
M = [[1,2,3], [4,5,6], [7,8,9]]
N = [[2,2,2], [3,3,3], [4,4,4]]
# 第五題解法之一 # =>實現效果1 [2, 4, 6, 12, 15, 18, 28, 32, 36] # =>實現效果2 [[2, 4, 6], [12, 15, 18], [28, 32, 36]] # 實現效果 1 lst_new = [] for i in range(len(M)) : for j in range(len(N)) : res = M[i][j] * N[i][j] lst_new.append(res) print(lst_new) # 推導式寫法 res = [M[i][j]*N[i][j] for i in range(len(M)) for j in range(len(N))] print(res) # 實現效果 2 lst_new = [] for i in range(len(M)) : lst_new2 = [] for j in range(len(N)) : res = M[i][j] * N[i][j] lst_new2.append(res) lst_new.append(lst_new2) print(lst_new) # 推導式寫法 res = [[M[i][j]*N[i][j] for j in range(len(M))] for i in range(len(N))] print(res)
集合推導式
集合推導式和列表推導式的用法基本一樣,但是外面使用大括號包括,得到的數據是一個集合。
例題:
''' 案例: 滿足年齡在18到21,存款大于等于5000,小于等于5500的人 開卡格式為:尊貴VIP卡老X(姓氏),否則開卡格式為:摳腳大漢老X(姓氏) 把開卡的種類統計出來 ''' lst = [ {"name": "劉鑫煒", "age": 18, "money": 10000}, {"name": "劉聰", "age": 19, "money": 5100}, {"name": "劉子豪", "age": 20, "money": 4800}, {"name": "孔祥群", "age": 21, "money": 2000}, {"name": "宋云杰", "age": 18, "money": 20} ] # 常規寫法 setvar = set() for i in lst: if (18 <= i['age'] <= 21) and (5000 <= i['money'] <= 5500): res = '尊貴VIP老' + i['name'][0] else: res = '摳腳老漢' + i['name'][0] setvar.add(res) print(setvar) # {'尊貴VIP老劉', '摳腳老漢劉', '摳腳老漢孔', '摳腳老漢宋'} # 打印顯示只有4個元素,是因為集合的自動去重 # 使用集合推導式 # 推導式只能使用單項分支,但是可以在返回值使用三元運算符 setvar = { "尊貴VIP卡老" + i["name"][0] if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else "摳腳大漢卡老" + i["name"][0] for i in lst} print(setvar) # {'摳腳大漢卡老孔', '摳腳大漢卡老劉', '尊貴VIP卡老劉', '摳腳大漢卡老宋'}
字典推導式
字典推導式也是一樣的用法,但是字典的數據是以鍵值對的形式存在的,所以返回的數據、或者要將返回的數據變成兩個,以對應鍵值。
基礎語法:
將列表中的鍵值對的變成一個字典
lst = [{'A': 'a'}, {'B': 'b'}] dct = {k:v for i in lst for k,v in i.items()} print(dct) # {'A': 'a', 'B': 'b'}
字典推導式常用以配合的函數
函數 | 作用 |
---|---|
enumerate | 枚舉,根據索引號碼將可迭代對象中的值一一配對成元組,返回迭代器。 |
zip | 將多個可迭代對象中的值一一對應組成元組,返回迭代器。 |
enumerate
功能:
枚舉,根據索引號碼 和 Iterable 中的值,一個一個拿出來配對組成元組,放入迭代器中,然后返回迭代器。
語法:
enumerate(iterable, [start = 0])
參數:
iterable:可迭代數據
start:可以選擇開始的索引號(默認從0開始索引)
基本語法:
from collections import Iterator lst = ['東', '南', '西', '北'] # 基本使用 it = enumerate(lst) # 實現功能返回迭代器 print(isinstance(it, Iterator)) # True # 強轉成列表 new_lst = list(it) print(new_lst) # [(0, '東'), (1, '南'), (2, '西'), (3, '北')] """ 可以看到里面的元列表中的數據和對應的索引號碼一一對應成了元組 """
上面的舉例當中,如果使用字典推導式和enumerate函數配合,就可以用一句話達成組成一個字典的目的。
from collections import Iterator lst = ['東', '南', '西', '北'] # enumerate 配合使用字典推導式 變成字典 dct = {k: v for k, v in enumerate(lst)} print(dct) # {0: '東', 1: '南', 2: '西', 3: '北'}
zip
功能:
將多個Iterable中的值,一個一個拿出來配對組成元組放入迭代器中,如果某個元素多出,沒有匹配項就會被舍棄。
語法:
zip(iterable, iterable1, ……)
參數就是一個個的可迭代對象。
基本語法:
下面的舉例當中,將三個列表中的元素以一一對應組成元組,但是最小的列表中只有三個元素,所以只能一一對應組成三對元組,而多出的元素就被舍棄。
lst1 = [1, 2, 3, 4, 5] lst2 = ['a', 'b', 'c', 'd'] lst3 = ['A', 'B', 'C'] it = zip(lst1, lst2, lst3) lst = list(it) print(lst) # [(1, 'a', 'A'), (2, 'b', 'B'), (3, 'c', 'C')]
為什么沒有元組推導式?
推導式我們到此學習完了,但是我們就發現,推導式就是在容器中使用一個for循環而已,為什么沒有元組推導式?
優先使用推導式
在有的時候,我們需要在一個列表或者其它的一些容器中存放大量的值,我們一般會怎么使用呢?比如在初始化一個列表的時候我們使用for循環和append的方法去創建嗎?
這里大家注意,如果條件允許的話,那么我們一定是要優先使用推導式而不是for循環加append的方式,原因很簡單,因為底層邏輯的不同,使推導式的執行速度相比for循環加append更快。
import time # 列表循環插入數據 start_time = time.perf_counter() lst = [] for i in range(15000000): lst.append(i) end_time = time.perf_counter() print(end_time - start_time) # 1.7453036000000002 """ 推導式比循環速度更快 """ start_time = time.perf_counter() new_lst1 = [i for i in range(15000000)] end_time = time.perf_counter() print(end_time - start_time) # 0.7337192000000001
經過測試我們可以看到,推導式的速度大約是for循環的2倍多,是什么導致的?還記得我們之前使用過的dis
模塊嗎?
import dis def loop(): lst = [] for i in range(10): lst.append(i) return lst def der(): lst = [i for i in range(10)] return lst dis.dis(loop) print('-' * 100) dis.dis(der)
結果如下:
??4 ??????????0 BUILD_LIST ??????????????0
??????????????2 STORE_FAST ??????????????0 (lst)
??5 ??????????4 SETUP_LOOP ?????????????26 (to 32)
??????????????6 LOAD_GLOBAL ?????????????0 (range)
??????????????8 LOAD_CONST ??????????????1 (10)
?????????????10 CALL_FUNCTION ???????????1
?????????????12 GET_ITER
????????>> ??14 FOR_ITER ???????????????14 (to 30)
?????????????16 STORE_FAST ??????????????1 (i)
??6 ?????????18 LOAD_FAST ???????????????0 (lst)
?????????????20 LOAD_ATTR ???????????????1 (append)
?????????????22 LOAD_FAST ???????????????1 (i)
?????????????24 CALL_FUNCTION ???????????1
?????????????26 POP_TOP
?????????????28 JUMP_ABSOLUTE ??????????14
????????>> ??30 POP_BLOCK
??7 ????>> ??32 LOAD_FAST ???????????????0 (lst)
?????????????34 RETURN_VALUE
-----------------------------------------------------------------------------
?11 ??????????0 LOAD_CONST ??????????????1 (<code object <listcomp> at 0x000002C71AD950C0, file "tset.py", line 11>)
??????????????2 LOAD_CONST ??????????????2 ('der.<locals>.<listcomp>')
??????????????4 MAKE_FUNCTION ???????????0
??????????????6 LOAD_GLOBAL ?????????????0 (range)
??????????????8 LOAD_CONST ??????????????3 (10)
?????????????10 CALL_FUNCTION ???????????1
?????????????12 GET_ITER
?????????????14 CALL_FUNCTION ???????????1
?????????????16 STORE_FAST ??????????????0 (lst)
?12 ?????????18 LOAD_FAST ???????????????0 (lst)
?????????????20 RETURN_VALUE
從上述結果中我們就是可以看出,在這種情況下,for循環因為開始定義列表、循環中的append方法的是使用,比推導式要多出幾個環節,因此速度相比之下變得很慢,這就是原因。
再次我們也再說一句,之后碰到關于速度和底層之類的疑惑的時候,就可以簡單的使用timeit
和dis
去驗證和簡答的理解。
原文鏈接:https://blog.51cto.com/msr20666/5285101
- 上一篇:淺談Redis的異步機制_Redis
- 下一篇:C#多線程之線程鎖_C#教程
相關推薦
- 2022-02-21 React事件綁定詳解_React
- 2022-07-08 Python基礎篇之字符串的最全常用操作方法匯總_python
- 2023-07-16 spring boot 實現token攔截
- 2022-12-25 pytorch中model.named_parameters()與model.parameters(
- 2022-10-17 Kotlin編程循環控制示例詳解_Android
- 2022-06-19 python繪制散點圖和折線圖的方法_python
- 2022-04-06 Python?numpy視圖與副本_python
- 2021-12-09 android藍牙簡單開發示例教程_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支