第037講:類和物件:面向物件程式設計
課堂小筆記
面向物件最重要的概念就是類(Class)和例項(Instance),必須牢記類是抽象的模板,比如Student類,而例項是根據類創建出來的一個個具體的“物件”,每個物件都擁有相同的方法,但各自的資料可能不同。
self是什麼?
Python的self就相當於C++的this指標。類是圖紙,物件是例項化的東西。由同一個類可以生成無數個物件,這些物件長得都很相似,都是來源於同一個類的屬性和方法,當一個物件的方法被呼叫的時候,物件會將自身作為第一個引數傳給這個self引數,接收到這個self的時候Python就知道你是哪一個物件在呼叫方法了。
為什麼都是呼叫kick方法,為啥結果不一樣。因為在呼叫的時候,a.kick()的這裡他有第一個引數,這個引數是隱藏的,就是把a這個物件的標誌傳進去;那setName()這裡的self就接收到了,self.name就會去找到這個a物件的name屬性,然後kick把他賦值打印出來。是Python默默在工作的。
(類裡面沒有定義的屬性都可以賦值,因為類是共有屬性,物件可以有自己的私有屬性)
你聽說過Python的魔法方法嗎?
被雙下劃線包圍。
__init__(self),稱為構造方法,魔力體現在:只要在例項化一個物件的時候,那麼這個方法就會在物件被建立的時候自動呼叫。(傳說中的構成函式?)
共有和私有
蒼井空是世界的,老婆是自己的!
name mangling 名字改編,名字重整。在Python中定義私有變數只需要在變數名或函式名前加上“__”兩個下劃線,那麼這個函式或者變數就變為私有的了。
可以通過p._Person__name
是偽私有。
課後測試題及答案
測試題:
0. 以下程式碼體現了面向物件程式設計的什麼特徵?
>>> "FishC.com".count('o') 1 >>> [1, 1, 2, 3, 5, 8].count(1) 2 >>> (0, 2, 4, 8, 12, 18).count(1) 0
都可以呼叫同一個方法,但是結果不一定相同。
1. 當程式設計師不想把同一段程式碼寫幾次,他們發明了函式解決了這種情況。當程式設計師已經有了一個類,而又想建立一個非常相近的新類,他們會怎麼做呢?
非常相近的新類,可以用繼承吧,繼承原先的類,再自己修改
2. self引數的作用是什麼?
用來接收物件的,可以讓Python知道是哪個物件在使用方法和屬性
3. 如果我們不希望物件的屬性或方法被外部直接引用,我們可以怎麼做?
可以使用“__”雙下劃線來使其私有化,雖然是偽私有,因為還是可以通過_類名__方法/屬性 來引用。
4. 類在例項化後哪個方法會被自動呼叫?
__init__()
5. 請解釋下邊程式碼錯誤的原因:
class MyClass: name = 'FishC' def myFun(self): print("Hello FishC!") >>> MyClass.name 'FishC' >>> MyClass.myFun() Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> MyClass.myFun() TypeError: myFun() missing 1 required positional argument: 'self' >>>
沒有一個物件傳給self引數,
動動手
0. 按照以下要求定義一個遊樂園門票的類,並嘗試計算2個成人+1個小孩平日票價。
平日票價100元
週末票價為平日的120%
兒童半票
答案:
class Ticket(): def __init__(self, weekend=False, child=False): self.exp = 100 if weekend: self.inc = 1.2 else: self.inc = 1 if child: self.discount = 0.5 else: self.discount = 1 def calcPrice(self, num): return self.exp * self.inc * self.discount * num >>> adult = Ticket() >>> child = Ticket(child=True) >>> print("2個成人 + 1個小孩平日票價為:%.2f" % (adult.calcPrice(2) + child.calcPrice(1))) 2個成人 + 1個小孩平日票價為:250.00
1. 遊戲程式設計:按以下要求定義一個烏龜類和魚類並嘗試編寫遊戲。(初學者不一定可以完整實現,但請務必先自己動手,你會從中學習到很多知識的^_^)
1 import random as r 2 3 legal_x = [0, 10] 4 legal_y = [0, 10] 5 6 class Turtle: 7 def __init__(self): 8 # 初始體力 9 self.power = 100 10 # 初始位置隨機 11 self.x = r.randint(legal_x[0], legal_x[1]) 12 self.y = r.randint(legal_y[0], legal_y[1]) 13 14 def move(self): 15 # 隨機計算方向並移動到新的位置(x, y) 16 new_x = self.x + r.choice([1, 2, -1, -2]) 17 new_y = self.y + r.choice([1, 2, -1, -2]) 18 # 檢查移動後是否超出場景x軸邊界 19 if new_x < legal_x[0]: 20 self.x = legal_x[0] - (new_x - legal_x[0]) 21 elif new_x > legal_x[1]: 22 self.x = legal_x[1] - (new_x - legal_x[1]) 23 else: 24 self.x = new_x 25 # 檢查移動後是否超出場景y軸邊界 26 if new_y < legal_y[0]: 27 self.y = legal_y[0] - (new_y - legal_y[0]) 28 elif new_y > legal_y[1]: 29 self.y = legal_y[1] - (new_y - legal_y[1]) 30 else: 31 self.y = new_y 32 # 體力消耗 33 self.power -= 1 34 # 返回移動後的新位置 35 return (self.x, self.y) 36 37 def eat(self): 38 self.power += 20 39 if self.power > 100: 40 self.power = 100 41 42 class Fish: 43 def __init__(self): 44 self.x = r.randint(legal_x[0], legal_x[1]) 45 self.y = r.randint(legal_y[0], legal_y[1]) 46 47 def move(self): 48 # 隨機計算方向並移動到新的位置(x, y) 49 new_x = self.x + r.choice([1, -1]) 50 new_y = self.y + r.choice([1, -1]) 51 # 檢查移動後是否超出場景x軸邊界 52 if new_x < legal_x[0]: 53 self.x = legal_x[0] - (new_x - legal_x[0]) 54 elif new_x > legal_x[1]: 55 self.x = legal_x[1] - (new_x - legal_x[1]) 56 else: 57 self.x = new_x 58 # 檢查移動後是否超出場景y軸邊界 59 if new_y < legal_y[0]: 60 self.y = legal_y[0] - (new_y - legal_y[0]) 61 elif new_y > legal_y[1]: 62 self.y = legal_y[1] - (new_y - legal_y[1]) 63 else: 64 self.y = new_y 65 # 返回移動後的新位置 66 return (self.x, self.y) 67 68 turtle = Turtle() 69 fish = [] 70 for i in range(10): 71 new_fish = Fish() 72 fish.append(new_fish) 73 74 while True: 75 if not len(fish): 76 print("魚兒都吃完了,遊戲結束!") 77 break 78 if not turtle.power: 79 print("烏龜體力耗盡,掛掉了!") 80 break 81 82 pos = turtle.move() 83 # 在迭代器中刪除列表元素是非常危險的,經常會出現意想不到的問題,因為迭代器是直接引用列表的資料進行引用 84 # 這裡我們把列表拷貝給迭代器,然後對原列表進行刪除操作就不會有問題了^_^ 85 for each_fish in fish[:]: 86 if each_fish.move() == pos: 87 # 魚兒被吃掉了 88 turtle.eat() 89 fish.remove(each_fish) 90 print("有一條魚兒被吃掉了...")