日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
講解一下Python推導(dǎo)式

Python 推導(dǎo)式是一種獨(dú)特的數(shù)據(jù)處理方式,可以從一個數(shù)據(jù)序列構(gòu)建另一個新的數(shù)據(jù)序列的結(jié)構(gòu)體,下面為大家講解一下Python 推導(dǎo)式使用方法。

創(chuàng)新互聯(lián)是專業(yè)的文縣網(wǎng)站建設(shè)公司,文縣接單;提供成都網(wǎng)站建設(shè)、做網(wǎng)站,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行文縣網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

1. 推導(dǎo)式分類與用法

1.1 列表推導(dǎo)

列表推導(dǎo)式是一種快速生成列表的方式。它一般用“[]”括起來,例如

>>> [i for i in range(10)]
[0,1, 2, 3, 4, 5, 6, 7, 8, 9]

這是一種最基本的用法,列表推導(dǎo)式先執(zhí)行for循環(huán),再把遍歷的元素(或者對元素的一些計(jì)算表達(dá)式)作為列表的元素返回一個列表。

>>> [i*i for i in range(10)]
[0,1, 4, 9, 16, 25, 36, 49, 64, 81]

它就相當(dāng)于

>>> l = []
>>> for i in range(10):
...   l.append(i*i)
...
>>>            

我們可以用列表推導(dǎo)快速初始化一個二維數(shù)組

m = [[0,0,0],
    [0,0,0],
    [0,0,0]
    ]

n = []
for row in range(3):
   r = []
   for col in range(3):
       r.append(0)
   n.append(r)
print(n)

用下面的式子就可以得到這個二維數(shù)組

>>> [[0]*3 for i in range(3)]
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

列表推導(dǎo)式有很多種形式

for循環(huán)前面加if…else…

這種生成的元素個數(shù)不會少,只是根據(jù)for循環(huán)的結(jié)果使用不同的表達(dá)式

# 如果i是5的倍數(shù),結(jié)果是i,否則就是0
>>> [i if i % 5 == 0 else 0 for i in range(20)]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 10, 0, 0, 0, 0, 15, 0, 0, 0, 0]

# 如果是偶數(shù)就加100,奇數(shù)就減100
>>> [i+100 if i % 2 == 0 else i-100 for i in range(10)]
[100, -99, 102, -97, 104, -95, 106, -93, 108, -91]

for循環(huán)后面加if…

這種會只取符合條件的元素,所以元素個數(shù)跟條件相關(guān)

# for循環(huán)的結(jié)果只選擇是偶數(shù)的
>>> [i for i in range(10) if i % 2 == 0]
[0, 2, 4, 6, 8]
# for循環(huán)的結(jié)果只選擇是2和3的倍數(shù)的
>>> [i for i in range(10) if i % 2 == 0 and i % 3 == 0]
[0, 6]
# for循環(huán)的結(jié)果只選擇偶數(shù),并且應(yīng)用str函數(shù)
>>> [str(i) for i in range(10) if i % 2 == 0]
['0', '2', '4', '6', '8']

嵌套循環(huán)

假如我們展開一個二維矩陣,如下面的m,我們可以用嵌套循環(huán)實(shí)現(xiàn)。

m = [[1,2,3],
    [4,5,6],
    [7,8,9]
    ]

n = []
for row in m:
   for col in row:
       n.append(col)
print(n)

用列表推導(dǎo),最外層的for循環(huán)得到的row,可以在內(nèi)層中使用

m = [[1,2,3],
    [4,5,6],
    [7,8,9]
    ]
n = [col for row in m for col in row]
print(n)

再比如下面這個例子

>>> [a + b for a in '123' for b in 'abc']
['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']

更多用法

列表推導(dǎo)的用法比較靈活,我們不一定要把所有的都掌握,但是要能看懂。

>>> dic = {"k1":"v1","k2":"v2"}
>>> a = [k+":"+v for k,v in dic.items()]
>>> a
['k1:v1', 'k2:v2']

1.2 集合推導(dǎo)

集合推導(dǎo)的語法與列表推導(dǎo)一樣,只是它是用”{}“,而且,集合會自動去重

>>> { i for i in range(10)}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> { 0 if i % 2 == 0 else 1 for i in range(10)}
{0, 1}

1.3 字典推導(dǎo)

字典推導(dǎo)的語法也與其他的類似,只不過在最前面的格式是key:value,而且也是會去重

>>> { i : i.upper() for i in 'hello world'}
{'h': 'H', 'e': 'E', 'l': 'L', 'o': 'O', ' ': ' ', 'w': 'W', 'r': 'R', 'd': 'D'}
>>> { str(i) : i*i for i in range(10)}
{'0': 0, '1': 1, '2': 4, '3': 9, '4': 16, '5': 25, '6': 36, '7': 49, '8': 64, '9': 81}

1.4 元組推導(dǎo)?不存在的

既然用[]就能做列表推導(dǎo),那用()是不是就能做元組推導(dǎo)了?不是的,因?yàn)?)被用在了一種特殊的對象上:生成器(generator)。

>>> a = (i for i in range(10))
>>> print(a)

  
    at 0x000001A6100869C8> >>> 
   type(a) 
   
    'generator'> 
   
  

生成器是一個順序產(chǎn)生元素的對象,只能順序訪問,只能前進(jìn),而且只能遍歷一次。

可以使用next()函數(shù)取下一個元素,取不到就會報(bào)StopIteration異常,也可以使用for循環(huán)遍歷。

生成式?jīng)]法用下標(biāo)訪問,用next訪問直到報(bào)異常

>>> a = (i for i in range(0,2))
>>> a[0]
Traceback (most recent call last):
 File "  " , line 1, in 
  
    TypeError: 
   'generator' object is not subscriptable >>> next(a) 0 >>> next(a) 1 >>> next(a) Traceback (most recent call last):  File 
   "  " , line 1, 
   in 
   
     StopIteration 
   
  

用for循環(huán)遍歷

>>> a = (i for i in range(0,2))
>>> for i in a:
...   print(i)
...
0
1

先用next訪問,再用for循環(huán)

>>> a = (i for i in range(0,3))
>>> next(a)
0
>>> for i in a:
...   print(i)
...
1
2

我們可以加上list,tuple,set等做強(qiáng)轉(zhuǎn),但是list和set就沒必要了,如果想初始化成tuple,就用tuple做強(qiáng)轉(zhuǎn)。強(qiáng)轉(zhuǎn)的時候不需要再加多余的括號。

>>> a = tuple(i for i in range(0,3))
>>> a
(0, 1, 2)
>>> a = tuple( (i for i in range(0,3)) )
>>> a
(0, 1, 2)

生成式是惰式計(jì)算的,就是你確實(shí)用到這個元素了,它才去計(jì)算,好處就是節(jié)省了內(nèi)存,但是壞處是不能隨機(jī)訪問。

2. 推導(dǎo)式的性能

2.1 列表推導(dǎo)式與循環(huán)的性能

我們用timeit模塊去比較一下性能。

import timeit

def getlist1():  
   l = []  
   for i in range(10000):
       l.append(i)
   return l

def getlist2():
   return [i for i in range(10000)]

# 各執(zhí)行10000次
t1 = timeit.timeit('getlist1()',"from __main__ import getlist1", number=10000)
t2 = timeit.timeit('getlist2()',"from __main__ import getlist2", number=10000)

print('循環(huán)方式:',t1)
print('推導(dǎo)式方式:',t2)

執(zhí)行結(jié)果如下:

循環(huán)方式: 5.343517699991935
推導(dǎo)式方式: 2.6003115000057733

可見循環(huán)的方式比推導(dǎo)式慢了一倍,為什么會有這個問題呢?我們直接反編譯看這兩個的區(qū)別,用dis模塊可以反編譯Python代碼,產(chǎn)生字節(jié)碼。

源代碼及行數(shù)如下

getlist1的反編譯如下,左邊紅色對應(yīng)源代碼的行數(shù),藍(lán)色圈內(nèi)就是第6行代碼對應(yīng)的字節(jié)碼,我們可以看到,它有一個傳參并且調(diào)用方法append的過程,調(diào)用函數(shù)的代價(jià)是比較大的。

再來看一下列表推斷的反編譯結(jié)果

首先從字節(jié)碼數(shù)量上來比列表推斷就比用循環(huán)調(diào)append要少的多,而且列表推斷沒有使用方法調(diào)用,直接用了這個指令LIST_APPEND,在Python官網(wǎng)上的解釋是這樣的。

實(shí)際上這個解釋是有誤導(dǎo)性,字節(jié)碼中使用LIST_APPEND和在Python代碼中調(diào)用append是完全不一樣的,只不過這種底層的東西沒有很多人關(guān)心,它們的功能是一樣的。在2008年的時候就有人給Python代碼提patch,希望能自動將list.append()進(jìn)行優(yōu)化,直接優(yōu)化成LIST_APPEND而不是通過函數(shù)調(diào)用,但是目前還沒被采納。

提出者希望能在編譯的時候加一些選項(xiàng),比如像gcc可以使用-O1,-O2等進(jìn)行不同級別的優(yōu)化,但是目前CPython是沒有這些選項(xiàng)的,因?yàn)榇蠖鄶?shù)的Python開發(fā)者并不關(guān)心性能。

如果我們把上面的列表換成集合或者字典,差別會更大,所以能用推導(dǎo)式的地方盡量用推導(dǎo)式,可以提高性能。

2.2 列表推導(dǎo)式與生成器推導(dǎo)式的性能

其實(shí)這兩個并不具備可比性,因?yàn)樯傻慕Y(jié)果并不是一個東西。我們可以很容易的預(yù)測,產(chǎn)生生成器的推導(dǎo)式性能要好于列表推導(dǎo)式,但是用的時候生成器就不如列表了。

import timeit

def getlist1():  
   return [i for i in range(10000)]

def getlist2():
   return (i for i in range(10000))

# 各執(zhí)行10000次
t1 = timeit.timeit('getlist1()',"from __main__ import getlist1", number=10000)
t2 = timeit.timeit('getlist2()',"from __main__ import getlist2", number=10000)

print('列表:',t1)
print('生成器:',t2)

def getlist11():  
   a = [i for i in range(10000)]
   sum = 0
   for i in a:
       sum += i

def getlist22():
   a = (i for i in range(10000))
   sum = 0
   for i in a:
       sum += i

# 各執(zhí)行10000次
t1 = timeit.timeit('getlist11()',"from __main__ import getlist11", number=10000)
t2 = timeit.timeit('getlist22()',"from __main__ import getlist22", number=10000)

print('列表:',t1)
print('生成器:',t2)

執(zhí)行結(jié)果:

列表: 2.5977418000111356
生成器: 0.006076899997424334
列表: 6.336311199993361
生成器: 9.181903699995019

生成器產(chǎn)生的性能遠(yuǎn)大于列表,但是遍歷的時候不如列表,但是總體上看好像生成器好。不過不要忘了,生成器不能隨機(jī)訪問,而且只能用一次。所以這兩種對象,就是在合適的地方用合適的類型,不一定哪一種比哪一種更好。


分享標(biāo)題:講解一下Python推導(dǎo)式
文章鏈接:http://www.dlmjj.cn/article/cdihdsh.html