你知道如下語法之間的區別嗎?程序員
[x for x in range(5)]
(x for x in range(5))
tuple(range(5))
複製代碼
本文將向您介紹這裏的區別。express
首先,對列表進行簡短回顧(在其餘編程語言中一般稱爲「數組」):django
列表是一種能夠表示爲元素集合的數據。一個簡單的列表以下所示:[0, 1, 2, 3, 4, 5]
列表將全部可能類型的數據和數據組合做爲其元素:編程
>>> a = 12
>>> b = "this is text"
>>> my_list = [0, b, ['element', 'another element'], (1, 2, 3), a]
>>> print(my_list)
[0, 'this is text', ['element', 'another element'], (1, 2, 3), 12]
複製代碼
列表能夠編入索引。您可使用如下語法訪問任何單個元素或元素組:數組
>>> a = ['red', 'green', 'blue']
>>> print(a[0])
red
複製代碼
與字符串不一樣,列表在Python中是可變的。這意味着您能夠替換,添加或刪除元素。
您可使用for循環和range()函數建立列表。bash
>>> my_list = []
>>> for x in range(10):
... my_list.append(x * 2)
...
>>> print(my_list)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
複製代碼
一般被視爲Python中函數式編程的一部分,列表推導容許您使用包含較少代碼的for循環建立列表。app
使用列表推導來查看前一個示例的實現:編程語言
>>> comp_list = [x * 2 for x in range(10)]
>>> print(comp_list)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
複製代碼
上面的示例過於簡單,可讓您瞭解語法。使用更簡單的list(range(0, 19, 2))功能能夠實現相同的結果。函數式編程
您還能夠在推導的第一部分中使用更復雜的修改器,或添加將過濾列表的條件。像這樣的東西:函數
>>> comp_list = [x ** 2 for x in range(7) if x % 2 == 0]
>>> print(comp_list)
[4, 16, 36]
複製代碼
另外一個可用選項是使用列表推導來組合多個列表並建立列表列表。乍一看,語法彷佛很複雜。將列表視爲外部序列和內部序列可能會有所幫助。
當您想要經過組合兩個現有列表來建立列表列表時,是時候展現列表推導的強大功能了:
>>> nums = [1, 2, 3, 4, 5]
>>> letters = ['A', 'B', 'C', 'D', 'E']
>>> nums_letters = [[n, l] for n in nums for l in letters]
#the comprehensions list combines two simple lists in a complex list of lists.
>>> print(nums_letters)
>>> print(nums_letters)
[[1, 'A'], [1, 'B'], [1, 'C'], [1, 'D'], [1, 'E'], [2, 'A'], [2, 'B'], [2, 'C'], [2, 'D'], [2, 'E'], [3, 'A'], [3, 'B'], [3, 'C'], [3, 'D'], [3, 'E'], [4, 'A'], [4, 'B'], [4, 'C'], [4, 'D'], [4, 'E'], [5, 'A'], [5, 'B'], [5, 'C'], [5, 'D'], [5, 'E']]
>>>
複製代碼
讓咱們用文本嘗試它,或者說字符串對象是正確的。
>>> iter_string = "some text"
>>> comp_list = [x for x in iter_string if x !=" "]
>>> print(comp_list)
['s', 'o', 'm', 'e', 't', 'e', 'x', 't']
複製代碼
推導不只限於列表。您也能夠建立dicts並設置推導。
>>> dict_comp = {x:chr(65+x) for x in range(1, 11)}
>>> type(dict_comp)
<class 'dict'>
>>> print(dict_comp)
{1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I', 9: 'J', 10: 'K'}
>>> set_comp = {x ** 3 for x in range(10) if x % 2 == 0}
>>> type(set_comp)
<class 'set'>
>>> print(set_comp)
{0, 8, 64, 512, 216}
複製代碼
若是你瞭解了迭代和迭代器,那麼理解生成器的概念會更容易。
Iterable是數據的「序列」,您可使用循環迭代。可迭代的最簡單可見示例能夠是整數列表 - [1, 2, 3, 4, 5, 6, 7]。能夠迭代其餘類型的數據,如字符串,dicts,元組,集合等。
基本上,任何具備iter()方法的對象均可以用做可迭代的。您可使用hasattr()解釋器中的函數進行檢查。
>>> hasattr(str, '__iter__')
True
>>> hasattr(bool, '__iter__')
False
複製代碼
迭代一系列數據時,就會實現迭代器協議。例如,當您使用for循環時,後臺發生如下狀況:
iter()在對象上調用第一個方法將其轉換爲迭代器對象。
在迭代器對象上調用該方法以獲取序列的下一個元素。 next()
若是StopIteration沒有要調用的元素,則會引起異常。
>>> simple_list = [1, 2, 3]
>>> my_iterator = iter(simple_list)
>>> print(my_iterator)
<list_iterator object at 0x7f66b6288630>
>>> next(my_iterator)
1
>>> next(my_iterator)
2
>>> next(my_iterator)
3
>>> next(my_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
複製代碼
在Python中,生成器提供了一種實現迭代器協議的便捷方式。Generator是一個使用帶有yield語句的函數建立的迭代。
生成器的主要特徵是按需評估元素。當您使用return語句調用普通函數時,只要遇到return語句,函數就會終止。
在帶有yield語句的函數中,函數的狀態從上次調用中「保存」,而且能夠在下次調用生成函數時被拾取
>>> def my_gen():
... for x in range(5):
... yield x
複製代碼
生成器表達式容許在沒有yield關鍵字的狀況下即時建立生成器。可是它們不能分享用yield函數建立的生成器的所有功能。
語法和概念相似於列表推導的語法和概念:
>>> gen_exp = (x ** 2 for x in range(10) if x % 2 == 0)
>>> for x in gen_exp:
... print(x)
0
4
16
36
64
複製代碼
在語法方面,惟一的區別是你使用括號而不是方括號。
列表推導和生成器表達式返回的數據類型不一樣。
>>> list_comp = [x ** 2 for x in range(10) if x % 2 == 0]
>>> gen_exp = (x ** 2 for x in range(10) if x % 2 == 0)
>>> print(list_comp)
[0, 4, 16, 36, 64]
>>> print(gen_exp)
<generator object <genexpr> at 0x7f600131c410>
複製代碼
生成器在列表中的主要優勢是它佔用的內存要少得多。咱們可使用sys.getsizeof()方法檢查兩種類型佔用的內存量。
注意:在Python 2中,使用range()函數實際上沒法反映大小方面的優點,由於它仍然將整個元素列表保存在內存中。可是,在Python 3中,這個例子是可行的,由於它range()返回一個範圍對象。
>>> from sys import getsizeof
>>> my_comp = [x * 5 for x in range(1000)]
>>> my_gen = (x * 5 for x in range(1000))
>>> getsizeof(my_comp)
9024
>>> getsizeof(my_gen)
88
複製代碼
生成器一次生成一個項目 - 所以它比列表更有內存效率。
例如,當您想迭代列表時,Python會爲整個列表保留內存。生成器不會將整個序列保留在內存中,而且只會根據須要「生成」序列的下一個元素。
可能會嚇到或勸阻新手程序員的第一件事就是教育材料的規模。這裏的訣竅是將每一個概念視爲語言提供的選項,您不該該同時學習全部語言概念和模塊。
總有不一樣的方法來解決同一個任務。把它做爲完成工做的另外一個工具。
查看更多文章:www.apexyun.com
公衆號:銀河系1號
聯繫郵箱:public@space-explore.com
(未經贊成,請勿轉載)