# 練習38.列表操作
你已經學過了列表。在你學習“while循環”的時候,你對列表進行過“追加(append)”操作,而且將列表的內容打印了出來。另外你應該還在附加題里研究過 Python 文檔,看了列表支持的其他操作。這已經是一段時間以前了,所以如果你不記得了的話,就回到本書的前面再復習一遍把。
找到了嗎?還記得嗎?很好。那時候你對一個列表執行了`append`函數。不過,你也許還沒有真正明白發生的事情,所以我們再來看看我們可以對列表進行什么樣的操作。
當你看到像 mystuff.append('hello') 這樣的代碼時,你事實上已經在 Python 內部激發了一個連鎖反應。以下是它的工作原理:
> 1. 1.Python 看到你用到了`mystuff`,于是就去找到這個變量。也許它需要倒著檢查看你有沒有在哪里用`=`創建過這個變量,或者檢查它是不是一個函數參數,或者看它是不是一個全局變量。不管哪種方式,它得先找到 mystuff 這個變量才行。
> 1. 一旦它找到了`mystuff`,就輪到處理句點`.`(period)這個操作符,而且開始查看`mystuff`內部的一些變量了。由于`mystuff`是一個列表,Python 知道它支持一些函數。
> 1. 接下來輪到了處理`append`。Python會將“append”和`mystuff`支持的所有函數的名稱一一對比,如果確實其中有一個叫`append`的函數,那么 Python 就會去使用這個函數。
> 1. 接下來 Python 看到了括號`(` (parenthesis) 并且意識到, “噢,原來這應該是一個函數”,到了這里,它就正常會調用這個函數了,不過這里的函數還要多一個參數才行。
> 1. 這個額外的參數其實是……`mystuff`!我知道,很奇怪是不是?不過這就是 Python 的工作原理,所以還是記住這一點,就當它是正常的好了。真正發生的事情其實是 `append(mystuff, 'hello')` ,不過你看到的只是 `mystuff.append('hello')` 。
大部分時候你不需要知道這些細節,不過如果你看到一個像這樣的 Python 錯誤信息的時候,上面的細節就對你有用了:
~~~
$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Thing(object):
... def test(hi):
... print "hi"
...
>>> a = Thing()
>>> a.test("hello")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test() takes exactly 1 argument (2 given)
>>>
~~~
就是這個嗎?嗯,這個是我在Python命令行下展示給你的一點魔法。你還沒有見過`class`不過后面很快就要碰到了。現在你看到 Python 說`test() takes exactly 1 argument (2 given)` (test() 只可以接受1個參數,實際上給了兩個)。它意味著 python 把 `a.test("hello")` 改成了`test(a,"hello")`,而有人弄錯了,沒有為它添加 `a`這個參數。
一下子要消化這么多可能有點難度,我們將做幾個練習,讓你頭腦中有一個深刻的印象。下面的練習將字符串和列表混在一起,看看你能不能在里邊找出點樂子來:
~~~
ten_things = "Apples Oranges Crows Telephone Light Sugar"
print "Wait there are not 10 things in that list. Let's fix that."
stuff = ten_things.split(' ')
more_stuff = ["Day", "Night", "Song", "Frisbee", "Corn", "Banana", "Girl", "Boy"]
while len(stuff) != 10:
next_one = more_stuff.pop()
print "Adding: ", next_one
stuff.append(next_one)
print "There are %d items now." % len(stuff)
print "There we go: ", stuff
print "Let's do some things with stuff."
print stuff[1]
print stuff[-1] # whoa! fancy
print stuff.pop()
print ' '.join(stuff) # what? cool!
print '#'.join(stuff[3:5]) # super stellar!
~~~
## 你看到的結果
~~~
$ python ex38.py
Wait there are not 10 things in that list. Let's fix that.
Adding: Boy
There are 7 items now.
Adding: Girl
There are 8 items now.
Adding: Banana
There are 9 items now.
Adding: Corn
There are 10 items now.
There we go: ['Apples', 'Oranges', 'Crows', 'Telephone', 'Light', 'Sugar', 'Boy', 'Girl', 'Banana', 'Corn']
Let's do some things with stuff.
Oranges
Corn
Corn
Apples Oranges Crows Telephone Light Sugar Boy Girl Banana
Telephone#Light
~~~
## 列表能實現什么
假設你打算創建一個基于釣魚的電腦游戲。如果你不知道什么是釣魚,花點時間在網上找到相關資料看一看。要做到這些,你需要里了解一些關于“撲克牌”的概念,并將它們變成你的Python程序。你必須用python寫出知道如何玩一副虛擬撲克牌的代碼,這樣人們就能把你的游戲當成真實的游戲來玩,即使它不是真的。你需要的是一副“撲克牌”結構,而程序員就稱之為“數據結構”。
什么是數據結構呢?如果你仔細想想,數據結構其實就是一種正式的構造(組織)一些數據(事實)的方法。真的就是這么簡單,盡管一些數據結構十分錯綜復雜,它們也僅僅是在程序中存儲數據的方式而已,這樣你就能用不同的方式訪問它們。
我將在下一節練習中更深入的講解這些,但是列表是程序員常用的數據結構之一。它們只是數據的有序列表,你可以通過線性索引來存儲或訪問它們。什么?記住我說過的話,只是因為一個程序員說過“列表是一個列表”并不意味著它比真實世界中的列表復雜多少。 讓我們以撲克牌為例:
> 1. 你有一堆有值的卡片。
> 1. 這些卡片式一堆,一列,或者可以從頭到尾排列這些卡片。
> 1. 你可以隨機的從頂部、中部或者底部取出卡片。
> 1. 如果你想找到某張特殊的卡片, 你必須一張一張的檢索這些卡片。
讓我們看看我說過什么:
“一個有序的列表”是的,撲克牌有第一張和最后一張"有一些你要存儲的事物"是的,卡片就是我要存儲的東西"可以隨機訪問"是的,在這副牌中我可以任意取出一張."是線性的"是的,如果我想找到特定的一張牌,我必須從頭開始按順序查找。"有索引的"差不多, 如果我讓你找到一副撲克牌的第19張,你就必須按照順序去數,直到你找到這一張。在python的列表中,計算機可以直接跳到你給出的索引處。這就是一個列表做的所有的事情,這么解釋應該給了你一個在編程中找到列表概念的方法吧。編程中的每一個概念通常都有與真實世界相關聯,至少在真實世界是有用的。如果你能找出虛擬的概念在真實世界中對應的概念,那你也可以通過這些找到數據結構到底是做什么的。
## 什么情況可以使用列表
當你有一些有東西能匹配列表數據結構的有用特性時,使用列表:
> 1. 如果你需要維護一組次序,記住,這是把次序編成列表,而不是給次序排序,列表不會幫你排序。
> 1. 如果你需要根據一個隨機數訪問列表內容,記住,這時候基數從0開始。
> 1. 如果你需要從頭到尾操作列表內容,記住,這就是for循環。
## 附加題
> 1. 將每一個被調用的函數以上述的方式翻譯成 Python 實際執行的動作。比如`more_stuff.pop()` 是 `pop(more_stuff)`.
> 1. 將這兩種方式翻譯為自然語言。
> 1. 上網閱讀一些關于“面向對象編程(Object Oriented Programming)”的資料。暈了吧?嗯,我以前也是。別擔心。你將從這本書學到足夠用的關于面向對象編程的基礎知識,而以后你還可以慢慢學到更多。
> 1. 查一下 Python中的 “class” 是什么東西。不要閱讀關于其他語言的 “class” 的用法,這會讓你更糊涂。
> 1. 如果你不知道我講的是些什么東西,別擔心。程序員為了顯得自己聰明,于是就發明了 Opject Oriented Programming,簡稱為 OOP,然后他們就開始濫用這個東西了。如果你覺得這東西太難,你可以開始學一下 “函數編程(functional programming)”。
> 1. 找出10種可以放在列表中的例子,并用它們寫一些腳本。
## 常見問題
### Q:你沒有說說不要用while循環?
> 是的,請記住,當需要的時候,你可以打破規則,只有蠢人才會一直一味的遵從規則。
### Q:`join(' ', stuff)`為什么沒有生效?
> 文檔中關于join的內容,寫的沒有意義,`join`是使用一個字符串將列表內容鏈接起來的一個方法,你可以試試這么寫`' '.join(stuff).`.
### Q: 為什么你用了一個while循環?
> 試著用for循環改寫一下,看看哪個更簡單
### Q: `stuff[3:5]`實現了什么功能?
> 這句代碼從`stuff`中獲取了一個子集,包含stuff的第3和第4個元素,沒有包含第5個元素。它和`range(3,5)`的工作原理相近。
- 序言
- 前言
- 簡介
- 0:安裝和準備
- 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:IF 語句
- 30:Else 和 If
- 31:做出決定
- 32:循環和列表
- 33:while循環
- 34:訪問列表元素
- 35:分支和函數
- 36:設計和調試
- 37:復習符號
- 38:列表操作
- 39:字典,可愛的字典
- 40:模塊, 類和對象
- 41:學會說面向對象
- 42:對象、類、以及從屬關系
- 43:基本的面向對象的分析和設計
- 44:繼承Vs.包含
- 45:你來制作一個游戲
- 46:項目骨架
- 47:自動化測試
- 48:更復雜的用戶輸入
- 49:寫代碼語句
- 50:你的第一個網站
- 51:從瀏覽器獲取輸入
- 52:開始你的web游戲
- 來自老程序員的建議
- 下一步
- 附錄A:命令行教程
- 簡介
- 安裝和準備
- 路徑, 文件夾, 名錄 (pwd)
- 如果你迷路了
- 創建一個路徑 (mkdir)
- 改變當前路徑 (cd)
- 列出當前路徑 (ls)
- 刪除路徑 (rmdir)
- 目錄切換(pushd, popd)
- 生成一個空文件(Touch, New-Item)
- 復制文件 (cp)
- 移動文件 (mv)
- 查看文件 (less, MORE)
- 輸出文件 (cat)
- 刪除文件 (rm)
- 退出命令行 (exit)
- 下一步