本書適合學習Python3的入門讀者,也適用對編程一無所知,但渴望用編程改變世界的朋友們!本書提倡理解為主,應用為王。因此,只要有可能,小甲魚(作者)都會通過生動的實例來讓大家理解概念。 雖然這是一本入門書籍,但本書的“野心”可并不止于“初級水平”的教學。本書前半部分是基礎的語法特性講解,后半部分圍繞著Python3在爬蟲、Tkinter和游戲開發等實例上的應用。 編程知識深似海,小甲魚沒辦法僅通過一本書將所有的知識都灌輸給你,但能夠做到的是培養你對編程的興趣,提高你編寫代碼的水平,以及鍛煉你的自學能力。最后,本書貫徹的核心理念是: 實用、好玩,還有參與。
本書適合入門學習Python3的讀者,也適用于對編程一無所知,但渴望用編程改變世界的朋友!本書提倡理解為主,應用為王。本書前半部分講解Python3的基礎語法和高級特性,后半部分圍繞著Python3在爬蟲、Tkinter和游戲開發等實例上的應用。本書著重培養讀者對編程的興趣,提高你編寫代碼的水平,以及鍛煉讀者的自學能力。*后,本書貫徹的核心理念是:實用、好玩,還有參
前言
Life is short. You need Python.
——Bruce Eckel上邊這句話是Python社區的名言,翻譯過來就是“人生苦短,我用Python”。我和Python結緣于一次服務器的調試,從此便一發不可收拾。我從來沒有遇到一門編程語言可以如此干凈、簡潔,如果你有處女座情節,你一定會愛上這門語言。使用Python,可以說是很難寫出丑陋的代碼。我從來沒想過一門編程語言可以如此簡單,它太適合零基礎的朋友踏入編程的大門了,如果我有一個八歲的孩子,我一定會毫不猶豫地使用Python引導他學習編程,因為面對它,永遠不缺乏樂趣。Python雖然簡單,其設計卻十分嚴謹。盡管Python可能沒有C或C 這類編譯型語言運行速度那么快,但是C和C 需要你無時無刻地關注數據類型、內存溢出、邊界檢查等問題。而Python,它就像一個貼心的仆人,私底下為你都一一處理好,從來不用你操心這些,這讓你可以將全部心思放在程序的設計邏輯之上。有人說,完成相同的一個任務,使用匯編語言需要1000行代碼,使用C語言需要500行,使用Java只需要100行,而使用Python,可能只要20行就可以了。這就是Python,使用它來編程,你可以節約大量編寫代碼的時間。既然Python如此簡單,會不會學了之后沒什么實際作用呢?事實上你并不用擔心這個問題,因為Python可以說是一門“萬金油”語言,在Web應用開發、系統網絡運維、科學與數字計算、3D游戲開發、圖形界面開發、網絡編程中都有它的身影。目前越來越多的IT企業,在招聘欄中都有“精通Python語言優先考慮”的字樣。另外,就連Google都在大規模使用Python。好了,我知道過多的溢美之詞反而會使大家反感,所以我必須就此打住,剩下的就留給大家自己體驗吧。接下來簡單地介紹一下這本書。一年前,出版社的編輯老師無意間看到了我的一個同名的教學視頻,建議我以類似的風格撰寫一本書。當時我是受寵若驚的,也很興奮。剛開始寫作就遇到了不小的困難——如何將視頻中口語化的描述轉變為文字。當然,我希望盡可能地保留原有的幽默和風趣——畢竟學習是要快樂的。這確實需要花不少時間去修改,但我覺得這是值得的。 本書不假設你擁有任何一方面的編程基礎,所以本書不但適合有一定編程基礎,想學習Python3的讀者,也適合此前對編程一無所知,但渴望用編程改變世界的朋友!本書提倡理解為主,應用為王。因此,只要有可能,我都會通過生動的實例來讓大家理解概念。雖然這是一本入門書籍,但本書的“野心”可并不止于“初級水平”的教學。本書前半部分是基礎的語法特性講解,后半部分圍繞著Python3在爬蟲、Tkinter和游戲開發等實例上的應用。編程知識深似海,沒辦法僅通過一本書將所有的知識都灌輸給你,但我能夠做到的是培養你對編程的興趣,提高你編寫代碼的水平,以及鍛煉你的自學能力。最后,本書貫徹的核心理念是: 實用、好玩,還有參與。本書對應的系列視頻教程,可以在http://blog.fishc.com/category/python下載得到,也可掃描以下二維碼關注微信號進行觀看。
編者2016年7月
目錄
第1章就這么愉快地開始吧
1.1獲得Python
1.2從IDLE啟動Python
1.3失敗的嘗試
1.4嘗試點兒新的東西
1.5為什么會這樣
第2章用Python設計第一個游戲
2.1第一個小游戲
2.2縮進
2.3BIF
第3章成為高手前必須知道的一些基礎知識
3.1變量
3.2字符串
3.3原始字符串
3.4長字符串
3.5改進我們的小游戲
3.6條件分支
3.7while循環
3.8引入外援
3.9閑聊數據類型
3.9.1整型
3.9.2浮點型
3.9.3布爾類型
3.9.4類型轉換
3.9.5獲得關于類型的信息
3.10常用操作符
3.10.1算術操作符
3.10.2優先級問題
3.10.3比較操作符
3.10.4邏輯操作符
第4章了不起的分支和循環
4.1分支和循環
4.2課堂小練習
4.3結果分析
4.4Python可以有效避免“懸掛else”
4.5條件表達式(三元操作符)
4.6斷言
4.7while循環語句
4.8for循環語句
4.9range()
4.10break語句
4.11continue語句
第5章列表、元組和字符串
5.1列表: 一個“打了激素”的數組
5.1.1創建列表
5.1.2向列表添加元素
5.1.3從列表中獲取元素
5.1.4從列表刪除元素
5.1.5列表分片
5.1.6列表分片的進階玩法
5.1.7一些常用操作符
5.1.8列表的小伙伴們
5.1.9關于分片“拷貝”概念的補充
5.2元組: 戴上了枷鎖的列表
5.2.1創建和訪問一個元組
5.2.2更新和刪除元組
5.3字符串
5.3.1各種內置方法
5.3.2格式化
5.4序列
第6章函數
6.1Python的樂高積木
6.1.1創建和調用函數
6.1.2函數的參數
6.1.3函數的返回值
6.2靈活即強大
6.2.1形參和實參
6.2.2函數文檔
6.2.3關鍵字參數
6.2.4默認參數
6.2.5收集參數
6.3我的地盤聽我的
6.3.1函數和過程
6.3.2再談談返回值
6.3.3函數變量的作用域
6.4內嵌函數和閉包
6.4.1global關鍵字
6.4.2內嵌函數
6.4.3閉包(closure)
6.5lambda表達式
6.6遞歸
6.6.1遞歸是“神馬”
6.6.2寫一個求階乘的函數
6.6.3這幫小兔崽子
6.6.4漢諾塔
第7章字典和集合
7.1字典: 當索引不好用時
7.1.1創建和訪問字典
7.1.2各種內置方法
7.2集合: 在我的世界里,你就是唯一
7.2.1創建集合
7.2.2訪問集合
7.2.3不可變集合
第8章永久存儲
8.1文件: 因為懂你,所以永恒
8.1.1打開文件
8.1.2文件對象的方法
8.1.3文件的關閉
8.1.4文件的讀取和定位
8.1.5文件的寫入
8.1.6一個任務
8.2文件系統: 介紹一個高大上的東西
8.3pickle: 腌制一缸美味的泡菜
第9章異常處理
9.1你不可能總是對的
9.2tryexcept語句
9.2.1針對不同異常設置多個except
9.2.2對多個異常統一處理
9.2.3捕獲所有異常
9.3tryfinally語句
9.4raise語句
9.5豐富的else語句
9.6簡潔的with語句
第10章圖形用戶界面入門
10.1導入EasyGui
10.2使用EasyGui
10.3修改默認設置
第11章類和對象
11.1給大家介紹對象
11.2對象=屬性 方法
11.3面向對象編程
11.3.1self是什么
11.3.2你聽說過Python的魔法方法嗎
11.3.3公有和私有
11.4繼承
11.4.1調用未綁定的父類方法
11.4.2使用super函數
11.5多重繼承
11.6組合
11.7類、類對象和實例對象
11.8到底什么是綁定
11.9一些相關的BIF
第12章魔法方法
12.1構造和析構
12.1.1__init__(self[, ...])
12.1.2__new__(cls[, ...])
12.1.3__del__(self)
12.2算術運算
12.2.1算術操作符
12.2.2反運算
12.2.3增量賦值運算
12.2.4一元操作符
12.3簡單定制
12.4屬性訪問
12.5描述符(property的原理)
12.6定制序列
12.7迭代器
12.8生成器(亂入)
第13章模塊
13.1模塊就是程序
13.2命名空間
13.3導入模塊
13.4__name__='__main__'
13.5搜索路徑
13.6包
13.7像個極客一樣去思考
第14章論一只爬蟲的自我修養
14.1入門
14.2實戰
14.2.1下載一只貓
14.2.2翻譯文本
14.3隱藏
14.3.1修改UserAgent
14.3.2延遲提交數據
14.3.3使用代理
14.4Beautiful Soup
14.5正則表達式
14.5.1re模塊
14.5.2通配符
14.5.3反斜杠
14.5.4字符類
14.5.5重復匹配
14.5.6特殊符號及用法
14.5.7元字符
14.5.8貪婪和非貪婪
14.5.9反斜杠 普通字母=特殊含義
14.5.10編譯正則表達式
14.5.11編譯標志
14.5.12實用的方法
14.6異常處理
14.6.1URLError
14.6.2HTTPError
14.6.3處理異常
14.7安裝Scrapy
14.8Scrapy爬蟲之初窺門徑
14.8.1Scrapy框架
14.8.2創建一個Scrapy項目
14.8.3定義Item容器
14.8.4編寫爬蟲
14.8.5爬
14.8.6取
14.8.7在Shell中嘗試Selector選擇器
14.8.8使用XPath
14.8.9提取數據
14.8.10使用item
14.8.11存儲內容
第15章GUI的最終選擇: Tkinter
15.1Tkinter之初體驗
15.2Label組件
15.3Button組件
15.4Checkbutton組件
15.5Radiobutton組件
15.6LabelFrame組件
15.7Entry組件
15.8Listbox組件
15.9Scrollbar組件
15.10Scale組件
15.11Text組件
15.11.1Indexes用法
15.11.2Marks用法
15.11.3Tags用法
15.12Canvas組件
15.13Menu組件
15.14Menubutton組件
15.15OptionMenu組件
15.16Message組件
15.17Spinbox組件
15.18PanedWindow組件
15.19Toplevel組件
15.20事件綁定
15.21事件序列
15.21.1type
15.21.2modifier
15.22Event對象
15.23布局管理器
15.23.1pack
15.23.2grid
15.23.3place
15.24標準對話框
15.24.1messagebox(消息對話框)
15.24.2filedialog(文件對話框)
15.24.3colorchooser(顏色選擇對話框)
第16章Pygame: 游戲開發
16.1安裝Pygame
16.2初步嘗試
16.3解惑
16.3.1什么是Surface對象
16.3.2將一個圖像繪制到另一個圖像上是怎么一回事
16.3.3移動圖像是怎么一回事
16.3.4如何控制游戲的速度
16.3.5Pygame的效率高不高
16.3.6我應該從哪里獲得幫助
16.4事件
16.5提高游戲的顏值
16.5.1顯示模式
16.5.2全屏才是王道
16.5.3使窗口尺寸可變
16.5.4圖像的變換
16.5.5裁剪圖像
16.5.6轉換圖片
16.5.7透明度分析
16.6繪制基本圖形
16.6.1繪制矩形
16.6.2繪制多邊形
16.6.3繪制圓形
16.6.4繪制橢圓形
16.6.5繪制弧線
16.6.6繪制線段
16.7動畫精靈
16.7.1創建精靈
16.7.2移動精靈
16.8碰撞檢測
16.8.1嘗試自己寫碰撞檢測函數
16.8.2sprite模塊提供的碰撞檢測函數
16.8.3實現完美碰撞檢測
16.9播放聲音和音效
16.10響應鼠標
16.10.1設置鼠標的位置
16.10.2自定義鼠標光標
16.10.3讓小球響應光標的移動頻率
16.11響應鍵盤
16.12結束游戲
16.12.1發生碰撞后獲得隨機速度
16.12.2減少“抖動”現象的發生
16.12.3游戲勝利
16.12.4更好地結束游戲
16.13經典飛機大戰
16.13.1游戲設定
16.13.2主模塊
16.13.3我方飛機
16.13.4響應鍵盤
16.13.5飛行效果
16.13.6敵方飛機
16.13.7提升敵機速度
16.13.8碰撞檢測
16.13.9完美碰撞檢測
16.13.10一個BUG
16.13.11發射子彈
16.13.12設置敵機“血槽”
16.13.13中彈效果
16.13.14繪制得分
16.13.15暫停游戲
16.13.16控制難度
16.13.17全屏炸彈
16.13.18發放補給包
16.13.19超級子彈
16.13.20三次機會
16.13.21結束畫面
參考文獻
第5章列表、元組和字符串
5.1列表: 一個“打了激素”的數組有時候需要把一堆東西暫時存儲起來,因為它們有某種直接或者間接的聯系,需要把它們放在某種“組”或者“集合”中,因為將來可能用得上。很多接觸過編程的朋友都知道或者聽說過數組。數組這個概念呢,就是把一大堆同種類型的數據挨個兒擺在一塊兒,然后通過數組下標進行索引。但數組有一個基本要求,就是你所放在一起的數據必須類型一致。由于Python的變量沒有數據類型,也就是說,Python是沒有數組的。但是呢,Python加入了更為強大的列表。Python的列表有多強大?如果把數組比作是一個集裝箱的話,那么Python的列表就是一個工廠的倉庫了。列表真的非常有用,基本上所有的Python程序都要使用到列表,包括之前的打飛機游戲,里邊的小飛機可以全部扔到一個列表中統一管理。5.1.1創建列表創建列表和創建普通變量一樣,用中括號括起一堆數據就可以了,數據之間用逗號隔開,這樣一個普普通通的列表就創建成功了:
number = [1, 2, 3, 4, 5]
我們說列表是打了激素的數組不是沒有道理的,可以創建一個魚龍混雜的列表:
mix = [1, "小甲魚", 3.14, [1, 2, 3]]
可以看到上邊這個列表里有整型、字符串、浮點型數據,甚至還可以包含著另一個列表。當然,如果實在想不到要往列表里邊塞什么數據的時候,可以先創建一個空列表:
empty = []
5.1.2向列表添加元素列表相當靈活,所以它的內容不可能總是固定的,現在就來教大家如何向列表添加元素吧。要向列表添加元素,可以使用append()方法:
number = [1, 2, 3, 4, 5]
number.append(6)
number
[1, 2, 3, 4, 5, 6]
可以看到,參數6已經被添加到列表number的末尾了。有讀者可能會問,這個方法調用怎么跟平時的BIF內置函數調用不一樣呢?嗯,因為append()不是一個BIF,它是屬于列表對象的一個方法。中間這個“.”,大家暫時可以理解為范圍的意思: append()這個方法是屬于一個叫作number的列表對象的。關于對象的知識,咱暫時只需要理解這么多,后邊再給大家介紹對象。同理,我們可以把數字7和8添加進去,但是我們發現似乎不能用append()同時添加多個元素:
number.append(7, 8)
Traceback (most recent call last):
File "pyshell#122", line 1, in module
number.append(7, 8)
TypeError: append() takes exactly one argument (2 given)
這時候就可以使用extend()方法向列表末尾添加多個元素:
number.extend(7, 8)
Traceback (most recent call last):
File "pyshell#123", line 1, in module
number.extend(7, 8)
TypeError: extend() takes exactly one argument (2 given)
哎呀,怎么又報錯了呢?!嗯,其實小甲魚是故意的。extend()方法事實上使用一個列表來擴展另一個列表,所以它的參數應該是一個列表:
number.extend([7, 8])
number
[1, 2, 3, 4, 5, 6, 7, 8]
好,我們又再一次向世界證明我們成功了!但是又發現了一個問題,到目前為止,我們都是往列表的末尾添加數據,那如果我想“插隊”呢?當然沒問題,想要往列表的任意位置插入元素,就要使用insert()方法。insert()方法有兩個參數: 第一個參數代表在列表中的位置,第二個參數是在這個位置處插入一個元素。不妨來試一下,讓數字0出現在列表number的最前邊:
number.insert(1, 0)
number
[1, 0, 2, 3, 4, 5, 6, 7, 8]
等等,不是說好插入到第一個位置嗎?怎么插入后0還是排在1的后邊呢?其實是這樣的: 凡是順序索引,Python均從0開始,同時這也是大多數編程語言約定俗成的規范。那么大家知道為什么要用0來表示第一個數嗎?是因為計算機本身就是二進制的,在二進制的世界里只有兩個數: 0和1,當然,0就是二進制里的第一個數了,所以嘛,秉承著這樣的傳統,0也就習慣用于表示第一個數。所以,正確的做法應該是:
number = [1, 2, 3, 4, 5, 6, 7, 8]
number.insert(0, 0)
number
[0, 1, 2, 3, 4, 5, 6, 7, 8]
5.1.3從列表中獲取元素跟數組一樣,可以通過元素的索引值(index)從列表獲取單個元素,注意,列表索引值是從0開始的:
name = ["雞蛋", "鴨蛋", "鵝蛋", "李狗蛋"]
name[0]
'雞蛋'
name[3]
'李狗蛋'
那按照這個方法讓“李狗蛋”和“鴨蛋”的位置互調:
name[1], name[3] = name[3], name[1]
name
['雞蛋', '李狗蛋', '鵝蛋', '鴨蛋']
5.1.4從列表刪除元素從列表刪除元素,這里也介紹三種方法: remove()、del和pop()。先演示一下用remove()刪除元素:
name.remove("李狗蛋")
name
['雞蛋', '鵝蛋', '鴨蛋']
使用remove()刪除元素,你并不需要知道這個元素在列表中的具體位置,只需要知道該元素存在列表中就可以了。如果要刪除的東西根本不在列表中,程序就會報錯:
name.remove("陳鴨蛋")
Traceback (most recent call last):
File "pyshell#138", line 1, in module
name.remove("陳鴨蛋")
ValueError: list.remove(x): x not in list
remove()方法并不能指定刪除某個位置的元素,這時就要用del來實現:
del name[1]
name
['雞蛋', '鴨蛋']
注意,del是一個語句,不是一個列表的方法,所以你不必在它后邊加上小括號()。另外,如果你想刪除整個列表,還可以直接用del加列表名刪除:
del name
name
Traceback (most recent call last):
File "pyshell#142", line 1, in module
name
NameError: name 'name' is not defined
最后,演示用pop()方法“彈出”元素:
name = ["雞蛋", "鴨蛋", "鵝蛋", "李狗蛋"]
name.pop()
'李狗蛋'
name.pop()
'鵝蛋'
name
['雞蛋', '鴨蛋']
大家看到了,pop()方法默認是彈出列表中的最后一個元素。但這個pop()方法其實還可以靈活運用,當你為它加上一個索引值作為參數的時候,它會彈出這個索引值對應的元素:
name = ["雞蛋", "鴨蛋", "鵝蛋", "李狗蛋"]
name.pop(2)
'鵝蛋'
name
['雞蛋', '鴨蛋', '李狗蛋']
5.1.5列表分片利用索引值,每次可以從列表獲取一個元素,但是人總是貪心的,如果需要一次性獲取多個元素,有沒有辦法實現呢?利用列表分片(slice),可以方便地實現這個要求:
name = ["雞蛋", "鴨蛋", "鵝蛋", "李狗蛋"]
name[0:2]
['雞蛋', '鴨蛋']
很簡單對吧?只不過是用一個冒號隔開兩個索引值,左邊是開始位置,右邊是結束位置。這里要注意的一點是,結束位置上的元素是不包含的。利用列表分片,得到一個原來列表的拷貝,原來列表并沒有發生改變。列表分片也可以簡寫,我們說過Python就是以簡潔聞名于世,所以你能想到的“便捷方案”,Python的作者以及Python社區的小伙伴們都已經想到了,并付諸實踐,你要做的就是驗證一下是否可行:
name[:2]
['雞蛋', '鴨蛋']
name[1:]
['鴨蛋', '鵝蛋', '李狗蛋']
name[:]
['雞蛋', '鴨蛋', '鵝蛋', '李狗蛋']
如果沒有開始位置,Python會默認開始位置是0。同樣道理,如果要得到從指定索引值到列表末尾的所有元素,把結束位置省去即可。如果沒有放入任何索引值,而只有一個冒號,將得到整個列表的拷貝。再一次強調: 列表分片就是建立原列表的一個拷貝(或者說副本),所以如果你想對列表做出某些修改,但同時還想保持原來的那個列表,那么直接使用分片的方法來獲取拷貝就很方便了。5.1.6列表分片的進階玩法分片操作實際上還可以接收第三個參數,其代表的是步長,默認情況下(不指定它的時候)該值為1,來試試將其改成2會有什么效果?
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list1[0:9:2]
[1, 3, 5, 7, 9]
如果將步長改成2,那么每前進兩個元素才取一個出來。其實還可以直接寫成list1[::2]。如果步長的值是負數,例如-1,結果會怎樣呢?不妨試試看:
list1[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
是不是很有意思?這里步長設置為-1,就相當于復制一個反轉的列表。5.1.7一些常用操作符
此前學過的大多數操作符都可以運用到列表上:
list1 = [123]
list2 = [234]
list1 list2
False
list3 = ['abc']
list4 = ['bcd']
list3 list4
True
我們發現列表還是挺聰明的,竟然會懂得比較大小。那如果列表中不止一個元素呢?結果又會如何?
list1 = [123, 456]
list2 = [234, 123]
list1 list2
False
怎么會這樣?list1列表的和是123 456=579,按理應該比list2列表的和234 123=357要大,為什么list1>list2還會返回False呢?思考片刻后得出結論: Python的列表原來并沒有我們想象中那么“智能”(注: 在后邊講“魔法方法”的章節會教大家如何把列表改變得更加聰明),當列表包含多個元素的時候,默認是從第一個元素開始比較,只要有一個PK贏了,就算整個列表贏了。字符串比較也是同樣的道理(字符串比較的是第一個字符對應的ASCII碼值的大小)。我們知道字符串可以用加號( )來進行拼接,用乘號(*)來復制自身若干次。它們在列表身上也是可以實現的:
list1 = [123, 456]
list2 = [234, 123]
list3 = list1 list2
list3
[123, 456, 234, 123]
加號( )也叫連接操作符,它允許我們把多個列表對象合并在一起,其實就相當于extend()方法實現的效果。一般情況下建議大家使用extend()方法來擴展列表,因為這樣顯得更為規范和專業。另外,連接操作符并不能實現列表添加新元素的操作:
list1 = [123, 456]
list2 = list1 789
Traceback (most recent call last):
File "pyshell#177", line 1, in module
list2 = list1 789
TypeError: can only concatenate list (not "int") to list
所以如果要添加一個元素到列表中,用什么方法?嗯,可以用append()或者insert()方法,希望大家還記得。乘號(*)也叫重復操作符,重復操作符可以用于列表中:
list1 = [123]
list1 * 3
[123, 123, 123]
當然復合賦值運算符也可以用于列表:
list1 *= 5
list1
[123, 123, 123, 123, 123]
另外有個成員關系操作符大家也不陌生,我們是在談for循環的時候認識它的,成員關系操作符就是in和not in!
list1 = ["小豬", "小貓", "小狗", "小甲魚"]
"小甲魚" in list1
True
"小護士" not in list1
True
之前說過列表里邊可以包含另一個列表,那么對于列表中的列表元素,能不能使用in和not in測試呢?試試便知:
list1 = ["小豬", "小貓", ["小甲魚", "小護士"], "小狗"]
"小甲魚" in list1
False
"小護士" not in list1
True
可見,in和not in只能判斷一個層次的成員關系,這跟break和continue語句只能跳出一個層次的循環是一個道理。那要判斷列表里邊的列表的元素,應該先進入一層列表:
"小甲魚" in list1[2]
True
"小護士" not in list1[2]
False
順便說一下,前面提到使用索引號去訪問列表中的值,那么對于列表中的值,應該如何訪問呢?大家應該猜到了,其實跟C語言訪問二維數組的方法相似:
list1[2][0]
'小甲魚'
5.1.8列表的小伙伴們接下來認識一下列表的小伙伴們,那么列表有多少小伙伴呢?不妨讓Python自己告訴我們:
dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
產生了一個熟悉又陌生的列表,很多熟悉的方法似曾相識,例如append()、extend()、insert()、pop()、remove()都是學過的,F在再給大家介紹幾個常用的方法。count()這個方法的作用是計算它的參數在列表中出現的次數:
list1 = [1, 1, 2, 3, 5, 8, 13, 21]
list1.count(1)
2
index()這個方法會返回它的參數在列表中的位置:
list1.index(1)
0
可以看到,這里是返回第一個目標(1)在list1中的位置,index()方法還有兩個參數,用于限定查找的范圍。因此可以這樣查找第二個目標在list1的位置:
start = list1.index(1) 1
stop = len(list1)
list1.index(1, start, stop)
1
reverse()方法的作用是將整個列表原地翻轉,就是排最后的放到最前邊,排最前的放到最后,那么排倒數第二的就排在第二,以此類推:
list1 = [1, 2, 3, 4, 5, 6, 7, 8]
list1.reverse()
list1
[8, 7, 6, 5, 4, 3, 2, 1]
sort()這個方法是用指定的方式對列表的成員進行排序,默認不需要參數,從小到大排隊:
list1 = [8, 9, 3, 5, 2, 6, 10, 1, 0]
list1.sort()
list1
[0, 1, 2, 3, 5, 6, 8, 9, 10]
那如果需要從大到小排隊呢?很簡單,先調用sort()方法,列表會先從小到大排好隊,然后調用reverse()方法原地翻轉就可以啦。什么?太麻煩?好吧,大家真是越來越懶了……很好,大家離天才又近了一步小甲魚個人認為“懶”是創新發明的根源和動力。。其實,sort()這個方法其實有三個參數,其形式為sort(func, key, reverse)。func和key參數用于設置排序的算法和關鍵字,默認是使用歸并排序,算法問題不在這里討論,有興趣的朋友可以看一下小甲魚另一本不錯的教程: 《數據結構和算法》(C語言)。這里要討論sort()方法的第三個參數: reverse,沒錯,就是剛剛學的那個reverse()方法的那個reverse。不過這里作為sort()的一個默認參數,它的默認值是sort(reverse=False),表示不顛倒順序。因此,只需要把False改為True,列表就相當于從大到小排序:
list1 = [8, 9, 3, 5, 2, 6, 10, 1, 0]
list1.sort(reverse=True)
list1
[10, 9, 8, 6, 5, 3, 2, 1, 0]
5.1.9關于分片“拷貝”概念的補充上一節提到使用分片創建列表的拷貝:
list1 = [1, 3, 2, 9, 7, 8]
list2 = list1[:]
list2
[1, 3, 2, 9, 7, 8]
list3 = list1
list3
[1, 3, 2, 9, 7, 8]
看似一樣,對吧?但事實上呢?利用列表的一個小伙伴做以下修改,大家看看差別:
list1.sort()
list1
[1, 2, 3, 7, 8, 9]
list2
[1, 3, 2, 9, 7, 8]
list3
[1, 2, 3, 7, 8, 9]
可以看到list1已經從小到大排好了序,那list2和list3呢?使用分片方式得到的list2很有原則、很有格調,并不會因為list1的改變而改變,這個原理我待會兒跟大家說; 接著看list3……看,真正的墻頭草是list3,它竟然跟著list1改變了,這是為什么呢?不知道大家還記不記得在講解變量的時候說過,Python的變量就像一個標簽,就一個名字而已……還是給大家畫個圖好理解,如圖51所示。
圖51拷貝列表
這下大家應該明白了吧,為一個列表指定另一個名字的做法,只是向同一個列表增加一個新的標簽而已,真正的拷貝是要使用分片的方法。這個也是初學者最容易混淆的地方,大家以后寫代碼時一定要注意哦。
5.2元組: 戴上了枷鎖的列表早在三百多年前,孟德斯鳩在《輪法的精神》里邊就提到“一切擁有權力的人都容易濫用權力,這是萬古不變的一條經驗!钡欠彩菗碛写髾嗔Φ娜耍枷胗米陨淼膶嵺`證明孟德斯鳩是一個只會說屁話的家伙,但是他們好像都失敗了……由于列表過分強大,Python的作者覺得這樣似乎不妥,于是發明了列表的“表親”——元組。元組和列表最大的區別就是你可以任意修改列表中的元素,可以任意插入或者刪除一個元素,而對元組是不行的,元組是不可改變的(像字符串一樣),所以你也別指望對元組進行原地排序等高級操作了。5.2.1創建和訪問一個元組元組和列表,除了不可改變這個顯著特征之外,還有一個明顯的區別是,創建列表用的是中括號,而創建元組大部分時候用的是小括號(注意,我這里說的是大部分):
tuple1 = (1, 2, 3, 4, 5, 6, 7, 8)
tuple1
(1, 2, 3, 4, 5, 6, 7, 8)
訪問元組的方式與列表無異:
tuple1[1]
2
tuple1[5:]
(6, 7, 8)
tuple1[:5]
(1, 2, 3, 4, 5)
也使用分片的方式來復制一個元組:
tuple2 = tuple1[:]
tuple2
(1, 2, 3, 4, 5, 6, 7, 8)
如果你試圖修改元組的一個元素,那么抱歉,Python會很不開心:
tuple1[1] = 1
Traceback (most recent call last):
File "pyshell#7", line 1, in module
tuple1[1] = 1
TypeError: 'tuple' object does not support item assignment
我很好奇如果問你,列表的標志性符號是中括號([]),那么元組的標志性符號是什么?你會怎么回答呢?小甲魚相信百分之九十的朋友都會不假思索地回答: 小括號啊,有部分比較激進的朋友還可能會補充一句“小甲魚你傻啊?”好吧,這個問題其實也是大部分初學者所忽略和容易上當的,我們實驗一下:
temp = (1)
type(temp)
class 'int'
還記得type()方法吧,作用是返回參數的類型,這里它返回說temp變量是整型(int)。再試試:
temp = 1, 2, 3
type(temp)
class 'tuple'
噢,發現了吧?就算沒有小括號,temp還是元組類型,所以逗號(,)才是關鍵,小括號只是起到補充的作用。但是你如果想要創建一個空元組,那么你就直接使用小括號即可:
temp = ()
type(temp)
class 'tuple'
所以這里要注意的是,如果要創建的元組中只有一個元素,請在它后邊加上一個逗號(,),這樣可以明確告訴Python你要的是一個元組,不要拿什么整型、浮點型來忽悠你:
temp1 = (1)
type(temp1)
class 'int'
temp2 = (1, )
type(temp2)
class 'tuple'
temp3 = 1,
type(temp3)
class 'tuple'
為了證明逗號(,)起到了決定性作用,再給大家舉個例子:
8 * (8)
64
8 * (8,)
(8, 8, 8, 8, 8, 8, 8, 8)
5.2.2更新和刪除元組有朋友可能會說,剛才不是你自己說“元組是板上釘釘不能修改的嗎”?你現在又來談更新一個元組,小甲魚你這不是自己打臉嗎?大家不要激動……我們只是討論一個相對含蓄的做法(直接在同一個元組上更新是不可行的,除非你學習了后邊的“魔法方法”章節)。不知道大家還記不記得以前是如何更新一個字符串的?沒錯,是通過拷貝現有的字符串片段構造一個新的字符串的方式解決的,對元組也是使用同樣的方法:
temp = ("小雞", "小鴨", "小豬")
temp = temp[:2] ("小甲魚",) temp[2:]
temp
('小雞', '小鴨', '小甲魚', '小豬')
上面的代碼需要在“小鴨”和“小豬”中間插入“小甲魚”,那么通過分片的方法讓元組拆分為兩部分,然后再使用連接操作符( )合并成一個新元組,最后將原來的變量名(temp)指向連接好的新元組。不妨可以把這樣的做法稱為“貍貓換太子”。在這里就要注意了,逗號是必需的,小括號也是必需的!在談到列表的時候,小甲魚跟大家說有三個方法可以刪除列表里邊的元素,但是對于元組是不可變的原則來說,單獨刪除一個元素是不可能的,當然你可以用剛才小甲魚教給大家更新元組的方法,間接地刪除一個元素:
temp = temp[:2] temp[3:]
temp
('小雞', '小鴨', '小豬')
如果要刪除整個元組,只要使用del語句即可顯式地刪除一個元組:
del temp
temp
Traceback (most recent call last):
File "pyshell#30", line 1, in module
temp
NameError: name 'temp' is not defined
其實在日常使用中,很少使用del去刪除整個元組,因為Python的回收機制會在這個元組不再被使用到的時候自動刪除。最后小結一下哪些操作符可以使用在元組上,拼接操作符和重復操作符剛剛演示過了,關系操作符、邏輯操作符和成員關系操作符in和not in也可以直接應用在元組上,這跟列表是一樣的,大家自己實踐一下就知道了。關于列表和元組,我們今后會談得更多,目前,就先聊到這里。
5.3字符串或許現在又回過頭來談字符串,有些朋友可能會覺得沒必要。其實關于字符串,還有很多你可能不知道的秘密,由于字符串在日常使用中是如此常見,因此小甲魚抱著負責任的態度在本節把所知道的都倒出來跟大家分享一下。關于創建和訪問字符串,前面已經介紹過了。不過學了列表和元組,我們知道了分片的概念,事實上也可以應用于字符串之上:
str1 = "I love fishc.com!"
str1[:6]
'I love'
接觸過C語言的朋友應該知道,在C語言中,字符串和字符是兩個不同的概念(C語言用單引號表示字符,雙引號表示字符串)。但在Python并沒有字符這個類型,在Python看來,所謂字符,就是長度為1的字符串。當要訪問字符串的其中一個字符的時候,只需用索引列表或元組的方法來索引字符串即可:
str1[5]
'e'
字符串跟元組一樣,都是屬于“一言既出、駟馬難追”的家伙。所以一旦定下來就不能直接對它們進行修改了,如果必須要修改,我們就需要委曲求全……
str1[:6] " 插入的字符串" str1[6:]
'I love 插入的字符串 fishc.com!'
但是大家要注意,這種通過拼接舊字符串的各個部分得到新字符串的方式并不是真正意義上的改變原始字符串,原來的那個“家伙”還在,只是將變量指向了新的字符串(舊的字符串一旦失去了變量的引用,就會被Python的垃圾回收機制釋放掉)。像比較操作符、邏輯操作符、成員關系操作符等的操作跟列表和元組是一樣的,這里就不再啰唆了。5.3.1各種內置方法列表和元組都有它們的方法,大家可能覺得列表的方法已經非常多了,其實字符串更多呢。表51總結了字符串的所有方法及對應的含義。
表51Python字符串的方法
方法含義
capitalize()把字符串的第一個字符改為大寫
casefold()把整個字符串的所有字符改為小寫
center(width)將字符串居中,并使用空格填充至長度width的新字符串
count(sub[, start[, end]])返回sub在字符串里邊出現的次數,start和end參數表示范圍,可選
encode(encoding='utf8', errors='strict')以encoding指定的編碼格式對字符串進行編碼
endswith(sub[, start[, end]])檢查字符串是否以sub子字符串結束,如果是返回True,否則返回False。start和end參數表示范圍,可選
expandtabs([tabsize=8])把字符串中的tab符號(\t)轉換為空格,如不指定參數,默認的空格數是tabsize=8
find(sub[, start[, end]])檢測sub是否包含在字符串中,如果有則返回索引值,否則返回-1,start和end參數表示范圍,可選續表
方法含義
index(sub[, start[, end]])跟find方法一樣,不過如果sub不在string中會產生一個異常
isalnum()如果字符串至少有一個字符并且所有字符都是字母或數字則返回True,否則返回False
isalpha()如果字符串至少有一個字符并且所有字符都是字母則返回True,否則返回False
isdecimal()如果字符串只包含十進制數字則返回True,否則返回False
isdigit()如果字符串只包含數字則返回True,否則返回False
islower()如果字符串中至少包含一個區分大小寫的字符,并且這些字符都是小寫,則返回True,否則返回False
isnumeric()如果字符串中只包含數字字符,則返回True,否則返回False
isspace()如果字符串中只包含空格,則返回True,否則返回Falseistitle()如果字符串是標題化(所有的單詞都是以大寫開始,其余字母均小寫),則返回True,否則返回Falseisupper()如果字符串中至少包含一個區分大小寫的字符,并且這些字符都是大寫,則返回True,否則返回Falsejoin(sub)以字符串作為分隔符,插入到sub中所有的字符之間ljust(width)返回一個左對齊的字符串,并使用空格填充至長度為width的新字符串lower()轉換字符串中所有大寫字符為小寫lstrip()去掉字符串左邊的所有空格partition(sub)找到子字符串sub,把字符串分成一個3元組(pre_sub, sub, fol_sub),如果字符串中不包含sub則返回('原字符串', ' ', ' ')replace(old, new[, count])把字符串中的old子字符串替換成new子字符串,如果count指定,則替換不超過count次rfind(sub[, start[, end]])類似于find()方法,不過是從右邊開始查找rindex(sub[, start[, end]])類似于index()方法,不過是從右邊開始查找rjust(width)返回一個右對齊的字符串,并使用空格填充至長度為width的新字符串rpartition(sub)類似于partition()方法,不過是從右邊開始查找rstrip()刪除字符串末尾的空格split(sep=None, maxsplit=-1)不帶參數默認是以空格為分隔符切片字符串,如果maxsplit參數有設置,則僅分隔maxsplit個子字符串,返回切片后的子字符串拼接的列表splitlines(([keepends]))按照'\n'分隔,返回一個包含各行作為元素的列表,如果keepends參數指定,則返回前keepends行startswith(prefix[, start[, end]])檢查字符串是否以prefix開頭,是則返回True,否則返回False。start和end參數可以指定范圍檢查,可選strip([chars])刪除字符串前邊和后邊所有的空格,chars參數可以定制刪除的字符,可選swapcase()翻轉字符串中的大小寫title()返回標題化(所有的單詞都是以大寫開始,其余字母均小寫)的字符串translate(table)根據table的規則(可以由str.maketrans('a', 'b')定制)轉換字符串中的字符upper()轉換字符串中的所有小寫字符為大寫zfill(width)返回長度為width的字符串,原字符串右對齊,前邊用0填充。
這里選幾個常用的給大家演示一下用法,首先是casefold()方法,它的作用是將字符串的所有字符變為小寫:
str1 = "FishC"
str1.casefold()
'fishc'
count(sub[, start[, end]])方法之前試過了,就是查找sub子字符串出現的次數,可選參數(注: 在Python文檔中,用方括號([])括起來表示為可選)start和end表示查找的范圍:
str1 = "AbcABCabCabcABCabc"
str1.count('ab', 0, 15)
2
如果要查找某個子字符串在該字符串中的位置,可以使用find(sub[, start[, end]])或index(sub[, start[, end]])方法。如果找到了,則返回值是第一個字符的索引值; 如果找不到,則find()方法會返回-1,而index()方法會拋出異常(注: 異常是可以被捕獲并處理的錯誤,目前你可以認為就是錯誤):
str1 = "I love fishc.com"
str1.find("fishc")
7
str1.find("good")
-1
str1.index("fishc")
7
str1.index("good")
Traceback (most recent call last):
File "pyshell#12", line 1, in module
str1.index("good")
ValueError: substring not found
今后你可能會在很多文檔中看到join(sub)的身影,程序員喜歡用它來連接字符串,但它的用法也許會讓你感到詫異。join是以字符串作為分隔符,插入到sub字符串中所有的字符之間:
'x'.join("Test")
'Txexsxt'
'_'.join("FishC")
'F_i_s_h_C'
為什么說“程序員喜歡用join()來連接字符串”,我們不是有很好用的連接符號( )嗎?這是因為當使用連接符號( )去拼接大量的字符串時是非常低效率的,因為加號連接會引起內存復制以及垃圾回收操作。所以對于大量的字符串拼接來說,使用join()方法的效率要高一些:
'I' ' ' 'love' ' ' 'fishc.com'
'I love fishc.com'
' '.join(['I', 'love', 'fishc.com'])
'I love fishc.com'
replace(old, new[, count])方法如其名,就是替換指定的字符串:
str1 = "I love you"
str1.replace("you", "fishc.com")
'I love fishc.com'
split(sep=None, maxsplit=1)跟join()正好相反,split()用于拆分字符串:
str1 = ' '.join(['I', 'love', 'fishc.com'])
str1
'I love fishc.com'
str1.split()
['I', 'love', 'fishc.com']
str2 = '_'.join("FishC")
str2.split(sep='_')
['F', 'i', 's', 'h', 'C']
5.3.2格式化前面介紹了Python字符串大部分方法的使用,但唯獨漏了一個format()方法。因為小甲魚覺得format()方法跟本節的話題如出一轍,都是關于字符串的格式化,所以放一塊來講解。
那什么是字符串的格式化,又為什么需要對字符串進行格式化呢?舉個小例子給大家聽: 某天小甲魚召開了魚C國際互聯安全大會,到會的朋友有來自世界各地的各界精英人士,有小烏龜、喵星人、旺星人,當然還有米奇和唐老鴨。哇噻,那氣勢簡直跟小甲魚開了個動物園一樣……但是問題來了,大家交流起來簡直是雞同鴨講,不知所云!但是最后聰明的小甲魚還是把問題給解決了,其實也很簡單,各界都找一個翻譯就行了,統一都翻譯成普通話,那么問題就解決了……最后我們這個大會當然取得了卓越的成功并記入了吉尼斯動物大全。舉這個例子就是想跟大家說,格式化字符串,就是按照統一的規格去輸出一個字符串。如果規格不統一,就很可能造成誤會,例如十六進制的10跟十進制的10或二進制的10完全是不同的概念(十六進制10等于十進制16,二進制10等于十進制2)。字符串格式化,正是幫助我們糾正并規范這類問題而存在的。1. format()format()方法接受位置參數和關鍵字參數(位置參數和關鍵字參數在函數章節有詳細講解),二者均傳遞到一個叫作replacement字段。而這個replacement字段在字符串內由大括號({})表示。先看一個例子:
"{0} love {1}.{2}".format("I", "FishC", "com")
'I love FishC.com'
怎么回事呢?仔細看,字符串中的{0}、{1}和{2}應該跟位置有關,依次被format()的三個參數替換,那么format()的三個參數就叫作位置參數。那什么是關鍵字參數呢,再來看一個例子:
"{a} love .{c}".format(a="I", b="FishC", c="com")
'I love FishC.com'
{a}、和{c}就相當于三個標簽,format()將參數中等值的字符串替換進去,這就是關鍵字參數啦。另外,你也可以綜合位置參數和關鍵字參數在一起使用:
"{0} love .{c}".format("I", b="FishC", c="com")
'I love FishC.com'
但要注意的是,如果將位置參數和關鍵字參數綜合在一起使用,那么位置參數必須在關鍵字參數之前,否則就會出錯:
"{a} love .{0}".format(a="I", b="FishC", "com")
SyntaxError: non-keyword arg after keyword arg
如果要把大括號打印出來,你有辦法嗎?沒錯,這跟字符串轉義字符有點像,只需要用多一層大括號包起來即可(要打印轉義字符(\),只需用轉義字符轉義本身(\\)):
"{{0}}".format("不打印")
'{0}'
位置參數“不打印”沒有被輸出,這是因為{0}的特殊功能被外層的大括號({})剝奪,因此沒有字段可以輸出。注意,這并不會產生錯誤哦。最后來看另一個例子:
"{0}: {1:.2f}".format("圓周率", 3.14159)
'圓周率: 3.14'
可以看到,位置參數{1}跟平常有些不同,后邊多了個冒號。在替換域中,冒號表示格式化符號的開始,“.2”的意思是四舍五入到保留兩位小數點,而f的意思是定點數,所以按照格式化符號的要求打印出了3.14。2. 格式化操作符: %剛才講的是字符串的格式化方法,現在來談談字符串所獨享的一個操作符: %,有人說,這不是求余數的操作符嗎?是的,沒錯。當%的左右均為數字的時候,那么它表示求余數的操作; 但當它出現在字符中的時候,它表示的是格式化操作符。表52列舉了Python的格式化符號及含義。
表52Python格式化符號及含義
符號含義
%c格式化字符及其ASCII碼%s格式化字符串%d格式化整數%o格式化無符號八進制數%x格式化無符號十六進制數%X格式化無符號十六進制數(大寫)%f格式化浮點數字,可指定小數點后的精度%e用科學計數法格式化浮點數%E作用同%e,用科學計數法格式化浮點數%g根據值的大小決定使用%f或%e%G作用同%g,根據值的大小決定使用%f或%E
下面給大家舉幾個例子參考:
'%c' % 97
'a'
'%c%c%c%c%c' % (70, 105, 115, 104, 67)
'FishC'
'%d轉換為八進制是: %o' % (123, 123)
'123轉換為八進制是: 173'
'%f用科學計數法表示為: %e' % (149500000, 149500000)
'149500000.000000用科學計數法表示為: 1.495000e 08'
Python還提供了格式化操作符的輔助指令,如表53所示。
表53格式化操作符的輔助指令
符號含義
m.nm是顯示的最小總寬度,n是小數點后的位數結果左對齊 在正數前面顯示加號( )#在八進制數前面顯示'0o',在十六進制數前面顯示'0x64'或'0X64'0顯示的數字前面填充'0'代替空格
同樣給大家舉幾個例子供參考:
'%5.1f' % 27.658
' 27.7'
'%.2e' % 27.658
'2.77e 01'
'%10d' % 5
' 5'
'%-10d' % 5
'5 '
'%010d' % 5
'0000000005'
'%#X' % 100
'0X64'
3. Python的轉義字符及含義Python的部分轉義字符已經使用了一段時間,是時候來給它做個總結了,見表54。
表54轉義字符及含義
符號說明符號說明
\'單引號\r回車符\"雙引號\f換頁符\a發出系統響鈴聲\o八進制數代表的字符\b退格符\x十六進制數代表的字符\n換行符\0表示一個空字符\t橫向制表符(TAB)\\反斜杠\v縱向制表符
5.4序列聰明的你可能已經發現,小甲魚把列表、元組和字符串放在一塊兒來講解是有道理的,因為它們之間有很多共同點: 都可以通過索引得到每一個元素。 默認索引值總是從0開始(當然靈活的Python還支持負數索引)。 可以通過分片的方法得到一個范圍內的元素的集合。 有很多共同的操作符(重復操作符、拼接操作符、成員關系操作符)。我們把它們統稱為: 序列!下面介紹一些關于序列的常用BIF(內置方法)。1. list([iterable])list()方法用于把一個可迭代對象轉換為列表,很多朋友經常聽到“迭代”這個詞,但要是讓你解釋的時候,很多朋友就含糊其詞了: 迭代……迭代就是for循環嘛……這里小甲魚幫大家科普一下: 所謂迭代,是重復反饋過程的活動,其目的通常是為了接近并到達所需的目標或結果。每一次對過程的重復被稱為一次“迭代”,而每一次迭代得到的結果會被用來作為下一次迭代的初始值……就目前來說,迭代還就是一個for循環,但今后會介紹到迭代器,那個功能,那叫一個驚艷!好了,這里說list()方法要么不帶參數,要么帶一個可迭代對象作為參數,而這個序列天生就是可迭代對象(迭代這個概念實際上就是從序列中泛化而來的)。還是通過幾個例子給大家講解吧:
# 創建一個空列表
a = list()
a
[]
# 將字符串的每個字符迭代存放到列表中
b = list("FishC")
b
['F', 'i', 's', 'h', 'C']
# 將元組中的每個元素迭代存放到列表中
c = list((1, 1, 2, 3, 5, 8, 13))
c
[1, 1, 2, 3, 5, 8, 13]
事實上這個list()方法大家自己也可以動手實現對不對?很簡單嘛,實現過程大概就是新建一個列表,然后循環通過索引迭代參數的每一個元素并加入列表,迭代完畢后返回列表即可。大家課后不妨自己動動手來嘗試一下。2. tuple([iterable]) tuple()方法用于把一個可迭代對象轉換為元組,具體的用法和list()一樣,這里就不啰唆了。3. str(obj)str()方法用于把obj對象轉換為字符串,這個方法在前面結合int()和float()方法給大家講過,還記得吧?4. len(sub)len()方法用于返回sub參數的長度:
str1 = "I love fishc.com"
len(str1)
16
list1 = [1, 1, 2, 3, 5, 8, 13]
len(list1)
7
tuple1 = "這", "是", "一", "個", "元組"
len(tuple1)
5
5. max()max()方法用于返回序列或者參數集合中的最大值,也就是說,max()的參數可以是一個序列,返回值是該序列中的最大值; 也可以是多個參數,那么max()將返回這些參數中最大的一個:
list1 = [1, 18, 13, 0, -98, 34, 54, 76, 32]
max(list1)
76
str1 = "I love fishc.com"
max(str1)
'v'
max(5, 8, 1, 13, 5, 29, 10, 7)
29
6. min(…)min()方法跟max()用法一樣,但效果相反: 返回序列或者參數集合中的最小值。這里需要注意的是,使用max()方法和min()方法都要保證序列或參數的數據類型統一,否則會出錯。
list1 = [1, 18, 13, 0, -98, 34, 54, 76, 32]
list1.append("x")
max(list1)
Traceback (most recent call last):
File "pyshell#22", line 1, in module
max(list1)
TypeError: unorderable types: str() int()
min(123, 'oo', 456, 'xx')
Traceback (most recent call last):
File "pyshell#23", line 1, in module
min(123, 'oo', 456, 'xx')
TypeError: unorderable types: str() int()
人家說: 外行看熱鬧,內行看門道。分析一下這個錯誤信息。Python這里說“TypeError: unorderable types: str() > int()”,意思是說不能拿字符串和整型進行比較。這說明了什么呢?你看,str() > int(),說明max()方法和min()方法的內部實現事實上類似于之前提到的,通過索引得到每一個元素,然后將各個元素進行對比。所以不妨根據猜想寫出可能的代碼:
# 猜想下max(tuple1)的實現方式
temp = tuple1[0]
for each in tuple1:
if each temp:
temp = each
return temp
由此可見,Python的內置方法其實也沒啥了不起的,有些我們也可以自己實現,對吧?所以只要認真跟著本書的內容學習下去,很多看似如狼似虎的問題,將來都能迎刃而解!7. sum(iterable[, start])sum()方法用于返回序列iterable的總和,用法跟max()和min()一樣。但sum()方法有一個可選參數(start),如果設置該參數,表示從該值開始加起,默認值是0:
tuple1 = 1, 2, 3, 4, 5
sum(tuple1)
15
sum(tuple1, 10)
25
8. sorted(iterable, key=None, reverse=False)sorted()方法用于返回一個排序的列表,大家還記得列表的內建方法sort()嗎?它們的實現效果一致,但列表的內建方法sort()是實現列表原地排序; 而sorted()是返回一個排序后的新列表。
list1 = [1, 18, 13, 0, -98, 34, 54, 76, 32]
list2 = list1[:]
list1.sort()
list1
[-98, 0, 1, 13, 18, 32, 34, 54, 76]
sorted(list2)
[-98, 0, 1, 13, 18, 32, 34, 54, 76]
list2
[1, 18, 13, 0, -98, 34, 54, 76, 32]
9. reversed(sequence)reversed()方法用于返回逆向迭代序列的值。同樣的道理,實現效果跟列表的內建方法reverse()一致。區別是列表的內建方法是原地翻轉,而reversed()是返回一個翻轉后的迭代器對象。你沒看錯,它不是返回一個列表,是返回一個迭代器對象:
list1 = [1, 18, 13, 0, -98, 34, 54, 76, 32]
reversed(list1)
list_reverseiterator object at 0x000000000324F518
for each in reversed(list1):
print(each, end=',')
32,76,54,34,-98,0,13,18,1,
10. enumerate(iterable)enumerate()方法生成由二元組(二元組就是元素數量為二的元組)構成的一個迭代對象,每個二元組是由可迭代參數的索引號及其對應的元素組成的。舉個例子你就明白了:
str1 = "FishC"
for each in enumerate(str1):
print(each)
(0, 'F')
(1, 'i')
(2, 's')
(3, 'h')
(4, 'C')
11. zip(iter1 [,iter2 [...]])zip()方法用于返回由各個可迭代參數共同組成的元組,舉個例子比較容易理解:
list1 = [1, 3, 5, 7, 9]
str1 = "FishC"
for each in zip(list1, str1):
print(each)
(1, 'F')
(3, 'i')
(5, 's')
(7, 'h')
(9, 'C')
tuple1 = (2, 4, 6, 8, 10)
for each in zip(list1, str1, tuple1):
print(each)
(1, 'F', 2)
(3, 'i', 4)
(5, 's', 6)
(7, 'h', 8)
(9, 'C', 10)