Python|切片,迭代和列表生成器

分享一些最近剛學到的實用而有趣的Python特性。請多指教。

本教程適用於Python 2.7,部分語法與Python 3.x有區別。

理解本文章中的內容的前置要求是:

  • 了解python內置的常用數據類型
  • 了解類型(class)和對象(object)
  • 了解for循環的基本用法

通過這篇文章,我希望讀者們能夠:

  • 掌握切片功能和列表生成器功能的用法
  • 理解可迭代對象和迭代器對象的關係,以及用迭代器進行迭代的原理。

關於迭代部分的說明不甚詳細,如有紕漏煩請各位在評論區指出。

  1. 切片

切片功能能夠按照「每n個元素取出1個元素」的規律對list, tuple和str類型的數據進行操作。

我們先定義一個變數,list直觀一些。

>>> a = range(100)n

用切片功能取a中第10個元素至第19個元素中的每個元素,可以寫成如下形式:

>>> a[10:20]n[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]n

冒號前面的數字是起始項的索引,冒號後面的數字是結束項的索引,切片會切到結束項的前一個,例如:

>>> a[90:99]n[90, 91, 92, 93, 94, 95, 96, 97, 98]n

如果切取部分是從第0項開始的話,冒號前面的0可以省略。例如:

>>> a[0:10]n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]n>>> a[:10]n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]n

同樣,如果切取部分的最後一項就是原list的最後一項的話,冒號後面的數字也可以省略。例如:

>>> a[90:100]n[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]n>>> a[90:]n[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]n

既然list有倒數的索引功能,切片操作也同樣支持倒數的索引。例如:

>>> a[-20:-10]n[80, 81, 82, 83, 84, 85, 86, 87, 88, 89]n

如果冒號的前面和後面都什麼也不填呢?返回原list。

前面說了,切片可以「每隔n個元素取1個元素」,以上只演示了n = 1的情況,那麼如何讓n取1以外的數呢?

>>> a[:20:5]n[0, 5, 10, 15]n

只需要傳入第三個參數就行啦。

切片可以重複操作,例如

>>> a[::2][::5]n[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]nn>>> a = range(100000)n>>> a[::2][::3][::5][::7][::11][::13]n[0, 30030, 60060, 90090]n

切片也可以對數據類型為tuple和str的變數進行操作。一段字元串中的每一個字元被視為一項。

>>> b = tuple(range(100))n>>> b[50:60]n(50, 51, 52, 53, 54, 55, 56, 57, 58, 59)nn>>> c = "Chinas Prices Project"n>>> c[4::3]na isren

2. 迭代

迭代,就是指遍歷目標變數中的每一個元素的過程。for語句進行的就是迭代。但是除了用for語句進行循環外,還有一種某些情況下更加高效的迭代方式:迭代器。

迭代器是一種有著固定結構的變數類型,可以自己寫,也可以通過內置的iter()函數生成。比如:

>>> a = iter(range(5))n>>> type(a)n<type listiterator>n>>> for i in a:n... print in...n0n1n2n3n4n

既然我們可以直接運行for i in range(5),why bother? 請看下面的例子。

# 轉載自www.cnblogs.com/kaituorensheng/p/3826911.htmlnndef fab(max): n L = []n n, a, b = 0, 0, 1 n while n < max: n L.append(b) n a, b = b, a + b n n = n + 1n return Ln

如果我們取max = 1,000,000, 反正我試了,加速球直接變成99%,過了一會兒乾脆黑屏了。

但是如果使用迭代器呢?請看下面的例子。

# 轉載自www.cnblogs.com/kaituorensheng/p/3826911.htmlnnclass Fab(object): n def __init__(self, max): n self.max = max n self.n, self.a, self.b = 0, 0, 1 nn def __iter__(self): n return self nn def next(self): n if self.n < self.max: n r = self.b n self.a, self.b = self.b, self.a + self.b n self.n = self.n + 1 n return r n raise StopIterationnna = Fab(1000000)nfor i in a:n print in

這裡的Fab()就是一個迭代器對象。雖然代碼很長,但是在這段代碼里max取多少都沒有問題,我賦了個一百萬然後晾一邊讓它刷了一個小時,內存佔用率沒怎麼變。

其中的原理是什麼呢?讓我們仔細看看這段定義。類型Fab共包含三個方法,其中__iter__()和next()我們沒有見過。構成一個可迭代對象的要點是,存在一個可以返回迭代器的__iter__()方法;構成一個迭代器的要點就是,存在一個可以被重複調用的next()方法。可以看出,這裡的Fab不僅是一個迭代器對象,也是一個可迭代對象。

讓我們先放下讓人頭疼的可迭代對象和迭代器對象,看看這段代碼被執行時都發生了什麼。事實上,python的for語句執行迭代器時的大概過程如下。

(不會用PS)

看完了這個圖,是不是感覺稍微明白了一點呢?

同時可以看出,某些情況下迭代器更加高效的原因是由於它不斷執行next(),它只返回數列的下一個數,也就是說同一時間內內存中只有一個數,因此當處理一些大容量的數據時較把所有數據都存在內存里的for循環要好得多。

我們回到上面的Fab。當for語句執行時,顯然前三個條件都滿足,第三個條件中__iter__()方法返回的是它本身,這是由於它本身包含一個能夠被重複調用的next()方法。

可迭代對象和迭代器對象並不一定要放在同一個對象中,例如:

# 轉載自http://python.jobbole.com/81916/nclass Iterable:n def __iter__(self):n return Iterator()nnclass Iterator:n def __init__(self):n self.start = -1n def __next__(self):n self.start += 2n if self.start > 10:n raise StopIterationn return self.startn

3. 列表生成式

如果我們想得到一些按照特殊規則產生的list,可以使用列表生成式。

比如說,我想生成從1到20的每個整數的平方,如果用循環的話,就是

a = range(1, 21)nl = []nfor i in a:n l.append(i * i)n

而如果用列表生成式的話,就是

[x * x for x in range(1, 21)]n

演算法是類似的,但是清爽許多。我們還可以在後面加上限制條件,比如說只取偶數得到的結果:

[x * x for x in range(1, 21) if x % 2 == 0]n

列表生成式還可以對字元串進行操作生成全排列:

[m + n for m in RRRGB for n in RGBBB]n

就醬,比起迭代來簡單多了。

更多項目介紹,請關注我們的項目專欄:Chinas Prices Project - 知乎專欄

項目聯繫方式:

  • 項目郵箱(@iGuo 的郵箱):zhangguocpp@163.com

  • 申請加入項目或者想給項目提供指導和幫助,請聯繫CHO@Suri :liuxiaomancpp@163.com
  • 知乎:@iGuo(CEO)@Suri(COO&CHO,Human) @林行健@Dementia (CTO)@張土不 (CFO)@張一(CRO,Research)

推薦閱讀:

沒有自學過任何計算機語言的人如何在大學中達到或超越那些」有底子」的大神?
Python的return如何理解?
在python中,怎樣計算list的累積和?不能用loop或者library的function。
python入門教程,求知友推薦?

TAG:Python入门 | Python |