# 習題 42: 物以類聚
雖說將函數放到字典里是很有趣的一件事情,你應該也會想到“如果 Python 能自動為你做這件事情該多好”。事實上也的確有,那就是 class 這個關鍵字。你可以使用 class 創建更棒的“函數字典”,比你在上節練習中做的強大多了。Class(類)有著各種各樣強大的功能和用法,但本書不會深入講這些內容,在這里,你只要你學會把它們當作高級的“函數字典”使用就可以了。
用到“class”的編程語言被稱作“Object Oriented Programming(面向對象編程)”語言。這是一種傳統的編程方式,你需要做出“東西”來,然后你“告訴”這些東西去完成它們的工作。類似的事情你其實已經做過不少了,只不過還沒有意識到而已。記得你做過的這個吧:
~~~
stuff = ['Test', 'This', 'Out']
print ' '.join(stuff)
~~~
其實你這里已經使用了 class。stuff 這個變量其實是一個 listclass (列表類)。而 ''.join(stuff) 里調用函數 join 的字符串 '' (就是一個空格)也是一個 class —— 它是一個 string class (字符串類)。到處都是 class!
還有一個概念是 object(物件),不過我們暫且不提。當你創建過幾個 class 后就會學到了。你怎樣創建 class 呢?和你創建 ROOMS 的方法差不多,但其實更簡單:
<table class="highlighttable"><tbody><tr><td class="linenos"> <div class="linenodiv"> <pre> 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
30
31
32
33
34
35
36
37</pre> </div> </td> <td class="code"> <div class="highlight"> <pre>class TheThing(object):
def __init__(self):
self.number = 0
def some_function(self):
print "I got called."
def add_me_up(self, more):
self.number += more
return self.number
# two different things
a = TheThing()
b = TheThing()
a.some_function()
b.some_function()
print a.add_me_up(20)
print b.add_me_up(30)
print a.number
print b.number
# Study this. This is how you pass a variable
# from one class to another. You will need this.
class TheMultiplier(object):
def __init__(self, base):
self.base = base
def do_it(self, m):
return m * self.base
x = TheMultiplier(a.number)
print x.do_it(b.number)
</pre> </div> </td> </tr></tbody></table>
Warning
嗯,你開始看到 Python 的“疣子”了。Python 是一門比較舊的語言,其中包含很多丑陋的設計決定。為了將這些丑陋設計掩蓋過去,他們就做了一些新的丑陋設計,然后告訴人們讓他們習慣這些新的壞設計。classTheThing(object) 就是其中一個例子。這里我就不展開講了,不過你也不必操心為什么你的 class 要在后面添一個(object) ,只要跟著這樣做就可以了,否則將來總有一天別的 Python 程序員會吼你讓你這樣做。后面我們再講為什么。
你看到參數里的 self 了吧?你知道它是什么東西嗎?對了,它就是 Python 創建的額外的一個參數,有了它你才能實現 a.some_function()`這種用法,這時它就會把\前者翻譯成``some_function(a) 執行下去。為什么用 self 呢?因為你的函數并不知道你的這個“實例”是來自叫 TheThing 或者別的名字的 class。所以你只要使用一個通用的名字 self 。這樣你寫出來的函數就會在任何情況下都能正常工作。
其實你可以使用 self 以外的別的字眼,不過如果你這樣做的話,你就會成為所有Python 程序員的眾之矢的,所以還是隨大流的好。只有變態才會在這里亂改,我教你的沒錯。對以后會讀到你的代碼的人好點兒,因為你現在的代碼10年以后所有的代碼都會是一團糟。
接下來,看到 __init__ 函數了嗎?這就是你為 Python class 設置內部變量的方式。你可以使用 . 將它們設置到 self 上面。另外看到我們使用了 add_me_up() 為你創建的 self.number 加值。后面你可以看到我們怎樣可以使用這種方法為數字加值,然后打印出來。
接著我創建了另一個叫 TheMutiplier 的 class,它的功能是做乘法。這樣的 class 其實是非常沒必要的,不過它向你展示了如何將變量和狀態從一個 class 傳遞到另一個 class。在這里我使用了 TheMultiplier.__init__ 來從 a.number 來獲取基本數值,我還將 b.number 傳遞到 TheMultiplier.do_it 以供調用。好好研究一下,你需要相關的知識來完成后面的加分習題。
Class 是很強大的東西,你應該好好讀讀相關的東西。盡可能多找些東西讀并且多多實驗。你其實知道它們該怎么用,只要試試就知道了。其實我馬上就要去練吉他了,所以我不會讓你寫練習了。你將使用 class 寫一個練習。
接下來我們將把習題41的內容重寫,不過這回我們將使用 class:
<table class="highlighttable"><tbody><tr><td class="linenos"> <div class="linenodiv"> <pre> 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76</pre> </div> </td> <td class="code"> <div class="highlight"> <pre>## Animal is-a object (yes, sort of confusing) look at the extra credit
class Animal(object):
pass
## ??
class Dog(Animal):
def __init__(self, name):
## ??
self.name = name
## ??
class Cat(Animal):
def __init__(self, name):
## ??
self.name = name
## ??
class Person(object):
def __init__(self, name):
## ??
self.name = name
## Person has-a pet of some kind
self.pet = None
## ??
class Employee(Person):
def __init__(self, name, salary):
## ?? hmm what is this strange magic?
super(Employee, self).__init__(name)
## ??
self.salary = salary
## ??
class Fish(object):
pass
## ??
class Salmon(Fish):
pass
## ??
class Halibut(Fish):
pass
## rover is-a Dog
rover = Dog("Rover")
## ??
satan = Cat("Satan")
## ??
mary = Person("Mary")
## ??
mary.pet = satan
## ??
frank = Employee("Frank", 120000)
## ??
frank.pet = rover
## ??
flipper = Fish()
## ??
crouse = Salmon()
## ??
harry = Halibut()
</pre> </div> </td> </tr></tbody></table>
### 你應該看到的結果
這個版本的游戲和你的上一版效果應該是一樣的,其實有些代碼都幾乎一樣。比較一下兩版代碼,弄懂其中不同的地方,重點需要理解這些東西:
1. 怎樣創建一個 classGame(object) 并且放函數到里邊去。
1. __init__ 是一個特殊的初始方法,可以預設重要的變量在里邊。
1. 為 class 添加函數的方法是將函數在 class 下再縮進一階,class 的架構就是通過縮進實現的,這點很重要。
1. 你在函數里的內容又縮進了一階。
1. 注意冒號的用法。
1. 理解 self 的概念,以及它在 __init__ 、 play 、 death 里是怎樣使用的。
1. 研究 play 里的 getattr 的功能,這樣你就能明白 play 所做的事情。其實你可以手動在 Python 命令行實驗一下,從而弄懂它。
1. 最后我們怎樣創建了一個 Game ,然后通過 play() 讓所有的東西運行起來。
### 加分習題
1. 研究一下 __dict__ 是什么東西,應該怎樣使用。
1. 再為游戲添加一些房間,確認自己已經學會使用 class 。
1. 創建一個新版本,里邊使用兩個 class,其中一個是 Map ,另一個是 Engine 。提示: 把 play 放到 Engine 里面。
- 譯者前言
- 前言:笨辦法更簡單
- 習題 0: 準備工作
- 習題 1: 第一個程序
- 習題 2: 注釋和井號
- 習題 3: 數字和數學計算
- 習題 4: 變量(variable)和命名
- 習題 5: 更多的變量和打印
- 習題 6: 字符串(string)和文本
- 習題 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: 來自 Percal 25 號行星的哥頓人(Gothons)
- 習題 42: 物以類聚
- 習題 43: 你來制作一個游戲
- 習題 44: 給你的游戲打分
- 習題 45: 對象、類、以及從屬關系
- 習題 46: 一個項目骨架
- 習題 47: 自動化測試
- 習題 48: 更復雜的用戶輸入
- 習題 49: 創建句子
- 習題 50: 你的第一個網站
- 習題 51: 從瀏覽器中獲取輸入
- 習題 52: 創建你的 web 游戲
- 下一步
- 老程序員的建議