【Python基礎(chǔ)】使用列表、字典和集合生成式來縮短代碼
編譯 | VK?
來源 | Towards Datas Science
在使用Python將近一年的時(shí)間里,我經(jīng)常遇到“生成式”這個(gè)詞,但我沒生成式它的確切含義或它所涵蓋的內(nèi)容。
直到最近,我才發(fā)現(xiàn),有了生成式后,我可以利用列表將我的代碼從多行縮短為一行。此外,這種代碼縮短方法不僅可以用于列表,還可以用于字典和集合。
本文試圖解釋生成式在列表、字典和集合的適用性,以及它們?nèi)绾螠p少日常編程所需的代碼量。
首先,生成式是可以在一行中創(chuàng)建列表、字典和集合的代碼片段。這樣就不必為for循環(huán)使用多行,而且還減少了使用map()、filter()和reduce()函數(shù)的需要。
它們由方括號(根據(jù)你要?jiǎng)?chuàng)建的數(shù)據(jù)類型而定)組成,其中包含一個(gè)表達(dá)式,后跟一個(gè)for子句和一個(gè)或多個(gè)if子句。表達(dá)式本身可以是任何東西,這意味著你可以將許多不同的對象放入列表中,只要它們是可編輯的。因此,從減少使用的行數(shù)和增加可讀性的角度來探討這些可能對代碼產(chǎn)生的影響是值得的。
列表
在python中,只需將項(xiàng)目放在方括號([])內(nèi),用逗號分隔,就可以創(chuàng)建列表,如下所示。
list1?=?[1,?2,?3,?"hello",?7.0,?52]
它們通常用于多種目的的編程中,但在長格式中編寫或使用for循環(huán)進(jìn)行編輯都會很麻煩。首先,在創(chuàng)建列表方面,小列表可能很容易以長格式打印出來,例如:
nums?=?[1,?2,?3,?4,?5,?6,?7,?8]
但當(dāng)這個(gè)值變長時(shí),即在0-50范圍內(nèi),甚至更長,它們可能會變得笨重。它們可以通過for循環(huán)使用range函數(shù)輕松創(chuàng)建,如下所示:
nums?=?[]
for?i?in?range(1,?51):
????nums.append(i)
print(nums)
#?out:?[1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34,?35,?36,?37,?38,?39,?40,?41,?42,?43,?44,?45,?46,?47,?48,?49,?50]
但是我們可以使用列表生成式將其縮短為一行,并且不需要append()方法。
nums?=?[i?for?i?in?range(1,51)]
print(nums)
#?out:?[1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30,?31,?32,?33,?34,?35,?36,?37,?38,?39,?40,?41,?42,?43,?44,?45,?46,?47,?48,?49,?50]
基本上,for循環(huán)放在一行中,同時(shí)初始化列表,從上面的示例中消除了對第一行和第二行代碼的需要。
當(dāng)我們開始為添加到列表中的數(shù)字添加條件時(shí),這就變得更加重要了,比如只允許偶數(shù)并且希望這些數(shù)字是平方的。同樣,也可以使用for循環(huán)生成,如下所示:
square_nums?=?[]
for?x?in?range(1,26):
????if?x?%?2?==?0:
????????square_nums.append(x**2)
print(square_nums)
#?out:?[4,?16,?36,?64,?100,?144,?196,?256,?324,?400,?484,?576]
但是,同樣可以使用列表生成式將其縮短為一行,從而減少對用于在范圍內(nèi)循環(huán)、創(chuàng)建條件并將結(jié)果附加到原始列表的行的需要。
square_nums?=?[x**2?for?x?in?range(1,26)?if?x?%?2?==?0]
print(square_nums)
#out:?[4,?16,?36,?64,?100,?144,?196,?256,?324,?400,?484,?576]
在這里,數(shù)字的轉(zhuǎn)換在行首執(zhí)行x**2,for循環(huán)在行中執(zhí)行,對于x在范圍(1,26),條件在末尾執(zhí)行,就好像x%2==0一樣。這本質(zhì)上使代碼更具可讀性,因?yàn)樗胁僮鞫荚谝恍兄袌?zhí)行,并減少了生成相同輸出所需的代碼量。
這還可以減少append()、map()、filter()或reduce()方法在創(chuàng)建新列表時(shí)對現(xiàn)有列表進(jìn)行操作的需要,再次降低代碼的復(fù)雜性并使其更具可讀性。
類似的例子是很容易獲得的,更多的信息可以很容易地通過其他文章在媒介,如這里和這里獲得。然而,值得注意的是,這些生成式也可以用于字典和集合。
字典
字典是一個(gè)無序的數(shù)據(jù)集合,可以改變和索引,使用大括號和鍵和值對編寫。在這里,鍵被用來訪問值,并且經(jīng)常被用來存儲信息,這些信息對這些信息是有用的。下面提供了一個(gè)示例,例如用于存儲分?jǐn)?shù)。
Grades?=?{
????"Steven":?57,
????"Jessica":?82,
????"William":?42,
????"Hussein":?78,
????"Mary":?65,
????}
????
print(Grades)
#?out:?{'Steven':?57,?'Jessica':?82,?'William':?42,?'Hussein':?78,?'Mary':?65}
與列表類似,有時(shí)也會很耗時(shí),因此可以使用for循環(huán)和條件語句來構(gòu)造,但可以更簡單地使用生成式來構(gòu)造。
例如,對于我們在上面創(chuàng)建的列表,我們不僅想知道數(shù)字的平方,而且還想存儲原始數(shù)字,這樣我們就可以使用它輕松地查找它的平方值。然后,我們可以簡單地創(chuàng)建一個(gè)包含鍵值對的字典,其中key代表原始數(shù)字,value代表數(shù)字的平方。使用for循環(huán):
#初始化空dict
even_squared_dict?=?{}
for?x?in?range(1,10):
????if?x?%?2?==?0:
????????even_squared_dict[x]?=?x**2
print(even_squared_dict)
#?out:?{2:?4,?4:?16,?6:?36,?8:?64}
但是使用字典生成式:
even_sqaured_dict?=?{x:?x**2?for?x?in?range(1,10)?if?x?%?2?==0}
print(even_squared_dict)
#?out:?{2:?4,?4:?16,?6:?36,?8:?64}
本質(zhì)上,這個(gè)和列表生成式之間的唯一區(qū)別是使用大括號來包含生成式,并將x放在冒號前面,以指示這表示鍵。
然后,還可以使用它來創(chuàng)建基于現(xiàn)有列表的字典。例如下面,字典生成式用于創(chuàng)建一個(gè)字典,其鍵為三位數(shù)的國家代碼,值為兩位數(shù)的國家代碼,其中兩位數(shù)代碼與三位數(shù)代碼的前兩位數(shù)相同。
ThreeCharCodes?=?["CAN",?"FIN",?"FRA",?"GAB",?"HKG",?"IMN",
??????????????????"MCO",?"NPL"]
??????????????????
cntryDict?=?{c:?c[:2]?for?c?in?threeCharCodes}
print(cntryDict)
#?out:?{'CAN':?'CA',?'FIN':?'FI',?'FRA':?'FR',?'GAB':?'GA',?'HKG':?'HK',?'IMN':?'IM',?'MCO':?'MC',?'NPL':?'NP'}
集合
最后,生成式也可以用于創(chuàng)建集合,集合是一種不同于列表或元組的數(shù)據(jù)類型,不能存儲同一元素的多次出現(xiàn)。
在這樣做時(shí),它存儲無序值,初始化方法是將一個(gè)列表傳遞給set()或使用大括號來包含由逗號分隔的值(盡管空的花括號將初始化字典)。下面提供了一個(gè)例子:
Fruits1?=?set(["apple",?"banana",?"cherry",?"apple"])
print(Fruits1)
Fruits2?=?{"orange",?"pear",?"grape",?"pear"}
print(Fruits2)
#?out:?{'apple',?'cherry',?'banana'}
???????{'grape',?'pear',?'orange'}
從這里可以清楚地看到,盡管向集合傳遞了多個(gè)apple或pear值,但只生成了一個(gè)實(shí)例。同樣,可以使用for循環(huán)生成這些命令,如下所示:
import?random
nums?=?set([])
for?x?in?range(25):
????y?=?random.randint(10,20)
????nums.add(y)
print(nums)
#?out:?{10,?12,?14,?15,?16,?17,?18,?20}
雖然25個(gè)隨機(jī)整數(shù)在10-20之間,但最終輸出僅包含8個(gè)唯一值,而不是列表中出現(xiàn)的25個(gè)值。同樣,使用對集合的生成式可以更簡潔地編寫這篇文章。
nums?=?{random.randint(10,20)?for?num?in?range(25)}
print(nums)
#?out:?{11,?12,?13,?14,?15,?16,?17,?19,?20}
因此,這種生成式與列表生成式的區(qū)別在于使用大括號,而不是包含生成式的方括號。
與列表和字典生成式類似,這也可以用于現(xiàn)有列表以生成集合。例如,如果我們想根據(jù)1.6的除法將公里改為英里,只需要唯一的值,并將其限制為小于100公里的值。
kms?=?[10,?12,?65,?40,?12,?75,?34,?65,?10,?10,?38,?100,?160,?200]
miles?=?{d/1.6?for?d?in?kms?if?d?100}
print(miles)
#?out:?{0.625,?0.75,?2.5,?2.125,?4.0625,?4.6875,?2.375}
總結(jié)
因此,生成式可以很容易地用于創(chuàng)建新的列表、詞典和集合。使用這些可以減少生成它們所需的行數(shù),并提高可讀性。它們可以用作append()、map()、filter()或reduce()函數(shù)的替換。
顯然,可以將它們放大以執(zhí)行更復(fù)雜的生成式,例如使用lambda函數(shù)、嵌套列表生成式或多條件語句。然而,在這樣做時(shí)值得注意的是,生成式可能很快變得難以理解,在這種情況下,值得回到創(chuàng)建函數(shù)或for循環(huán),以便在需要執(zhí)行多個(gè)操作時(shí)提高可讀性。
原文鏈接:https://towardsdatascience.com/the-use-of-list-dictionary-and-set-comprehensions-to-shorten-your-code-66e6dfeaae13
看到這里,說明你喜歡這篇文章,請點(diǎn)擊「在看」或順手「轉(zhuǎn)發(fā)」「點(diǎn)贊」。
往期精彩回顧
獲取一折本站知識星球優(yōu)惠券,復(fù)制鏈接直接打開:
https://t.zsxq.com/662nyZF
本站qq群704220115。
加入微信群請掃碼進(jìn)群(如果是博士或者準(zhǔn)備讀博士請說明):
