Python列表推導(list comprehension)VS 生成器表示式(generator expression)
你知道以下語法之間的區別嗎?
[x for x in range(5)] (x for x in range(5)) tuple(range(5))
本文將向您介紹這裡的區別。
關於列表的5個事實
首先,對列表進行簡短回顧(在其他程式語言中通常稱為“陣列”):
列表是一種可以表示為元素集合的資料。一個簡單的列表如下所示:[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()函式建立列表。
>>> 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迴圈建立列表。
使用列表推導來檢視前一個示例的實現:
>>> 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和Iterator之間的區別
如果你瞭解了迭代和迭代器,那麼理解生成器的概念會更容易。
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
生成器表示式(generator expression)
在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號
聯絡郵箱:[email protected]
(未經同意,請勿轉載)