# 練習41.學會說面向對象
在這個練習中,我要教你如何說“面向對象”,我要給你一些你需要知道定義的詞。然后我會給你一組你必須了解的句子,最后我會給你一大堆練習,你必須完成這練習題,將我給你的句子轉化成自己的詞匯。
## 單詞解釋
class(類):告訴python去創建一個新類型。object(對象):有兩種意思,事物的基本類型,或者事物的實例化。instance(實例):你通過python創建一個類所獲得的。def:用來在類中定義一個函數。self:在一個類包含的函數中,self是一個用來訪問實例或對象的變量。inheritance:概念,表示一個類可以繼承另一個類的特征,就像你和你的父母。composition:概念,表示一個類可以包含其他類,就像汽車輪子。 attribute:類所擁有的特性,通常是變量。is-a:慣用語,表示一個東西繼承自另一個東西(a),像在“鮭魚”是“魚”。 has-a:慣用語,表示由其他事情或有一個特征(a),如“鮭魚有嘴。”
花一些時間制作一些卡片用來記憶這些術語。像往常一樣,直到你完成這個練習后,這都不會有太多的意義,但是首先你需要知道的基本詞匯。
## 短語解釋
接下來,在左邊有一個Python代碼片段列表,右面是他們的解釋`class X(Y)`:創建一個叫X的類,并繼承Y。`class X(object): def __init__(self, J)`:類X有一個`__init__`方法,該方法有self和J兩個參數。`class X(object): def M(self, J)`:類X有一個叫M的函數,該函數有self和J兩個參數。`foo = X()`:給foo賦值為類X的一個實例。`foo.M(J)`:從foo里調用M函數,傳遞的參數為self和J。`foo.K = Q`:從foo里調用K屬性,并將其設置為Q。
你可以把上面看到的所有的X, Y, M, J, K, Q, 以及 foo 看做空白的坑,比如,我還可以這么寫:
> 1. 創建一個叫??的類繼承Y
> 1. 類??有一個`__init__`方法,該方法有self和??兩個參數。
> 1. 類??有一個叫??的函數,該函數有self和??兩個參數。
> 1. 給foo賦值為類??的一個實例。
> 1. 從foo里調用??函數,傳遞的參數為self和??。
> 1. 從foo里調用??屬性,并將其設置為??。
同樣的,把這些寫到卡片上,牢牢記住它們。卡片的前面寫上python的小段代碼,背面寫上它們的解釋,你要做到每當你看到正面的代碼段的時候,能立即說出后面的解釋。
## 組合練習
最后給你準備的是將單詞和短語結合起來練習。我希望你能做到下面的要求:
> 1. 準備好短語的卡片,并拼命的練習
> 1. 翻轉卡片,閱讀這些解釋語句,挑選出語句中包含單詞練習中單詞的卡片
> 1. 通過這些語句拼命練習這些單詞
> 1. 堅持練習,直到你厭煩了,休息一下,然后繼續練習
## 閱讀測試
下面有一個python腳本,這個腳本會以無盡模式訓練你,檢驗你所掌握的這些單詞。這是一個很簡單的腳本,它實現的功能是使用了一個叫做`urllib`的類庫來下載我提供的單詞列表。下面就是這個腳本,你需要正確的輸入并命名為`oop_test.py`:
~~~
import random
from urllib import urlopen
import sys
WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []
PHRASES = {
"class %%%(%%%):":
"Make a class named %%% that is-a %%%.",
"class %%%(object):\n\tdef __init__(self, ***)" :
"class %%% has-a __init__ that takes self and *** parameters.",
"class %%%(object):\n\tdef ***(self, @@@)":
"class %%% has-a function named *** that takes self and @@@ parameters.",
"*** = %%%()":
"Set *** to an instance of class %%%.",
"***.***(@@@)":
"From *** get the *** function, and call it with parameters self, @@@.",
"***.*** = '***'":
"From *** get the *** attribute and set it to '***'."
}
# do they want to drill phrases first
if len(sys.argv) == 2 and sys.argv[1] == "english":
PHRASE_FIRST = True
else:
PHRASE_FIRST = False
# load up the words from the website
for word in urlopen(WORD_URL).readlines():
WORDS.append(word.strip())
def convert(snippet, phrase):
class_names = [w.capitalize() for w in
random.sample(WORDS, snippet.count("%%%"))]
other_names = random.sample(WORDS, snippet.count("***"))
results = []
param_names = []
for i in range(0, snippet.count("@@@")):
param_count = random.randint(1,3)
param_names.append(', '.join(random.sample(WORDS, param_count)))
for sentence in snippet, phrase:
result = sentence[:]
# fake class names
for word in class_names:
result = result.replace("%%%", word, 1)
# fake other names
for word in other_names:
result = result.replace("***", word, 1)
# fake parameter lists
for word in param_names:
result = result.replace("@@@", word, 1)
results.append(result)
return results
# keep going until they hit CTRL-D
try:
while True:
snippets = PHRASES.keys()
random.shuffle(snippets)
for snippet in snippets:
phrase = PHRASES[snippet]
question, answer = convert(snippet, phrase)
if PHRASE_FIRST:
question, answer = answer, question
print question
raw_input("> ")
print "ANSWER: %s\n\n" % answer
except EOFError:
print "\nBye"
~~~
運行這個腳本,嘗試將這些“面向對象的短語”翻譯成自己的語言。你應該能看到字典`PHRASES`中包含了剛才練習的所有的短語。
## 練習將英語轉換為代碼
接下來,你可以使用"english"選項來執行腳本,這樣你可以反過來練習:
~~~
$ python oop_test.py english
~~~
記住這些短語使用的是無意義的詞匯。學習閱讀代碼的一部分是停止糾結這些用于變量和類的名字的真實意義。人們常常會在讀到一個像“cork”的詞時突然迷糊,因為這個詞會混淆他們的意義。在這個例子中,"Cork"只是用來作為一個類的名字。不要給它任何意義的解釋。
## 閱讀更多的代碼
你現在需要繼續閱讀更多的代碼,閱讀你找到的代碼中這些你剛學過的短語表達。你需要找出文件中所有的類,然后執行以下步驟:
> 1. 給出每一個類的名字,并說出這些類繼承哪些類
> 1. 列出每個類所包含的函數,以及函數需要的參數
> 1. 列出類所有的屬性
> 1. 對每個屬性,給出屬性的類型
這個練習的目的是通過閱讀真實的代碼,學習你剛才學到的短語是如何使用的。如果你練習的足夠所,你應該能看到這些模式在代碼中向你大聲呼喊,然而在這之前,他們是你所不知道的,只是模糊的空白而已。
## 常見問題
### Q: 這句代碼`result = sentence[:]`實現了什么
> 這是python中用來復制列表的一種方式。你使用了列表的分割切片語法`[:]`,得到列表從第一個到最后一個元素的切片。
### Q: 這個腳本很難跑起來啊
> 你需要輸入這些代碼并保證它能運行。這個腳本可能會有一些小問題,但是它并不復雜。試著用你到目前為止學到的東西來調試腳本,每輸入一行,確認一下是否與我的代碼一樣,并在網上搜索你所不了解的所有問題。
### Q: 這對我來說太難了!
> 你可以的,慢慢來,如果需要的話,你逐個字符的輸入,然后弄明白它是做什么的。
- 序言
- 前言
- 簡介
- 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)
- 下一步