今天我們開始學習面向對象的知識咯,之前我對面向對象也學的懵懵的,因為感覺知道好像又不是特別清楚,接下來我們一起來學習類和對象吧。零基礎的課程我都是看小甲魚的視頻學的,沒基礎的可以去這個網址下載視頻學習:http://blog.fishc.com/category/python
好了,我們開始進行學習吧,我們先來思考下,對象是什么?拋開程序代碼,我們想一下如果人是一個對象,那么這個對象有什么呢?
你是不是會說這個人長得怎么樣,眼睛咋樣,身高多少,對這個人的外貌特征進行描述,那么這個人能干什么呢?是不是能吃飯、走路、說話等。
那么你想下對於人這個對象來說是不是有特征和行為這兩大特性呢?那么對於程序來說對象也是如此,對象 = 屬性 + 方法
下面就是第一個實例,有屬性和方法,注意:類的名稱第一個字母為大寫,函數為小寫(約定俗成的習慣吧!)
#coding = utf-8 class Person: #無括號是舊的書寫方式,有括號是新的書寫方式 '''第一個簡單類實例_人''' height = 180 #屬性,是不是很像變量 weight = 70
#下面是方法 def run(self): #是不是就是一個個函數呢? print('我跑啊跑啊跑。。。') def sing(self): print('我唱歌唱啊唱啊。。。')
下面是類的實例化,很簡單的,直接賦值給一個變量,就可以通過變量來調用內的不同方法了

面向對象的特征:
- 封裝:對外部隱藏對象的工作細節
- 繼承:子類自動共享父類之間的數據和方法的機制
- 多態:可以對不同類的對象調用相同的方法,產生不同的結果
你可能發現上面定義類的時候函數的括號里面都有self這個東東,那這個是啥呢?
舉個例子大家看下:
class Test(): def __init__(self,name): #構造函數 self.name = name #name傳入后賦值 def run(self): print('%s 在跑。。。。'%self.name) #對name進行調用,記得寫self不然不知道你要調用的name在哪里
調用結果如下:

對於同一個類,那么我在調用的時候怎么區別是誰調的呢?self就是幫你解決這件事情的,self就是指的自己,也就是說是誰實例化的呢?a=Test就等同於Test(a),所以這個是不可缺少的,當前你可以不用self,可以用任意英文代替,不過大家都統一的事情你還是默認這樣寫吧。
類里面也有公有和私有之分,像我們之前看到的變量都是公有的,私有變量的話需要在變量前加入雙下划線“__”,這樣外面就不能調用了,當然實際上也是可以的,舉個例子看看吧。

其實__變量雖然訪問不到,但是也可以通過“_類__變量”進行訪問
下面給個題目大家做一下,我剛開始沒做出來,感覺有點難,后面看了下答案覺得還好,大家可以想一下:

答案如下:
import random as r legal_x = [0,10] legal_y = [0,10] class Turtle: def __init__(self): #初始體力 self.power = 100 #初始位置隨機 self.x = r.randint(legal_x[0],legal_x[1]) self.y = r.randint(legal_y[0],legal_y[1]) def move(self): #隨機計算方向並移動到新的位置(x,y) new_x = self.x + r.choice([1,2,-1,-2]) new_y = self.y + r.choice([1,2,-1,-2]) #檢查移動后是否超出場景x軸邊界 if new_x < legal_x[0]: self.x = legal_x[0] - (new_x - legal_x[0]) elif new_x > legal_x[1]: self.x = legal_x[1] - (new_x - legal_x[1]) else: self.x = new_x #檢查移動后是否超出場景y軸邊界 if new_y < legal_y[0]: self.y = legal_y[0] - (new_y - legal_y[0]) elif new_y > legal_y[1]: self.y = legal_y[1] - (new_y - legal_y[1]) else: self.y = new_y #體力消耗 self.power -= 1 #返回移動后的新位置 return(self.x, self.y) def eat(self): self.power += 20 if self.power > 100: self.power = 100 class Fish: def __init__(self): #初始位置隨機 self.x = r.randint(legal_x[0],legal_x[1]) self.y = r.randint(legal_y[0],legal_y[1]) def move(self): #隨機計算方向並移動到新的位置(x,y) new_x = self.x + r.choice([1,-1]) new_y = self.y + r.choice([1,-1]) #檢查移動后是否超出場景x軸邊界 if new_x < legal_x[0]: self.x = legal_x[0] - (new_x - legal_x[0]) elif new_x > legal_x[1]: self.x = legal_x[1] - (new_x - legal_x[1]) else: self.x = new_x #檢查移動后是否超出場景y軸邊界 if new_y < legal_y[0]: self.y = legal_y[0] - (new_y - legal_y[0]) elif new_y > legal_y[1]: self.y = legal_y[1] - (new_y - legal_y[1]) else: self.y = new_y #返回移動后的新位置 return(self.x, self.y) turtle = Turtle() fish = [] for i in range(10): new_fish = Fish() fish.append(new_fish) while True: if not len(fish): print("魚兒都吃完了,游戲結束!") break if not turtle.power: print("烏龜體力耗盡,掛掉了!") break pos = turtle.move() for each_fish in fish[:]: if each_fish.move() == pos: #魚兒被吃掉了 fish.remove(each_fish) turtle.eat()
寫完這個例子相信你對類其實了解一些了,接着我們來學習下類的繼承,聽名字好像又是什么高大上的東西,不怕其實是個很簡單的東東。
舉個簡單的例子,假設你寫了一個黃種人的類,但是又要寫黑人、白人的類呢?全部重新寫方法嗎?直接看代碼,來:
class Yello_person(): def __init__(self): self.skin = 'yellow' #self.name = 'liu' def eat(self): self.food = 'rice' print("%s種人在吃%s"%(self.skin,self.food)) class Black_person(Yello_person): #繼承Yello_person類的所有
def __init__(self): #重寫__init__這個構造函數,因此
self.skin = 'black'

大家看這就是繼承,可以繼承父類、基類、超類,繼承之后可以擁有父類的所有屬性和方法,如果重寫了就會讀取自己寫的屬性和方法,那么有個問題來了,如果我又想繼承部分屬性又想自己定義部分屬性呢?
那么接着看剛剛那么例子,用super()繼承即可:
class Yello_person(): def __init__(self): self.skin = 'yellow' self.name = 'liu' def eat(self): self.food = 'rice' print("叫%s的%s種人在吃%s"%(self.name,self.skin,self.food)) class Black_person(Yello_person): def __init__(self): super().__init__() #繼承父類的__init__()下的屬性 self.skin = 'black'

或者用下面這種方法,父類.__init__(self):
class Yello_person(): def __init__(self): self.skin = 'yellow' self.name = 'liu' def eat(self): self.food = 'rice' print("叫%s的%s種人在吃%s"%(self.name,self.skin,self.food)) class Black_person(Yello_person): def __init__(self): Yello_person.__init__(self) #繼承父類的__init__屬性 self.skin = 'black'
這兩個結果都是一樣的,都可以繼承,建議寫super(),因為修改的話只要修改一個地方的類就好了,第二種方法要修改很多處。
接下來說下多重繼承,其實就是class Person(class1,class2,class3),逗號隔開即可,看個實例:
class Yello_person(): def __init__(self): self.skin = 'yellow' def eat(self): self.food = 'rice' print("%s種人在吃%s"%(self.skin,self.food)) class Black_person(): def __init__(self): self.skin = 'black' class White_person(Black_person,Yello_person): pass
注意,如果繼承時Yello_person寫在前面則會打印這個
,所以多重繼承時,如果出現重復的,默認是選擇第一個類的屬性或方法。
接着看下下面的題目:
1、定義一個點(Point)類和直線(Line)類,使用getLen方法獲得直線的長度。
代碼如下:
import math class Point(): def __init__(self,x,y): self.x = x self.y = y def getX(self): return self.x def getY(self): return self.y class Line(): def __init__(self,p1,p2): self.x = p1.getX() - p2.getX() self.y = p1.getY() - p2.getY() self.len = math.sqrt(self.x*self.x + self.y*self.y) #獲取兩點之間的數學公式 def getLen(self): return self.len
之前說了類的繼承和多重繼承,那么如果說我們要定義一個房子,里面有人和家具,那么顯然用繼承是不合理的,因為這個類就是四不像了,那么這個時候該怎么辦呢?——組合,沒錯就是類的組合,舉個例子大家看下就好了;
class Person: def __init__(self,num): self.num = num class Jiaju: def __init__(self,num): self.num = num class room: def __init__(self,pnum,jnum): self.pnum = Person(pnum) #實例化人這個類然后賦值給一個變量 self.jnum = Jiaju(jnum) #實例化家具這個類然后賦值給一個變量
def retrunnum(self): print("房子里面總共有%d人和%d家具!"%(self.pnum.num, self.jnum.num))
運行結果可以看下:

組合就是將類的實例化放在新的類中,這樣就完成了組合
類、類對象和實例對象

這個圖是三個的關系圖,簡單說一下,剛開始看我覺得類定義和類對象分不清,實際上當類定義執行完后就變成了類對象,實例對象就是對類對象的實例化而已。
注意:類中的方法名與屬性名重名時,類將被屬性覆蓋,來看個實例:
>>> class Person: def name(self): print('king') >>> p1 = Person() >>> p1.name() king >>> p1.name = 1 >>> p1.name() Traceback (most recent call last): File "<pyshell#7>", line 1, in <module> p1.name() TypeError: 'int' object is not callable
綁定:python嚴格要求方法需要有實例才能被調用,這種限制其實就是python所謂的綁定概念。
1、issubclass(class, classinfo)
a、一個類被認為是其自身的子類
b、classinfo可以是類對象組成的元組,只要class是其中任何一個子類,則返回True
2、isinstance(object,classinfo)
a、如果第一個參數不是對象,則永遠返回False
b、如果第二個參數不是類或者由類對象組成的元組,會拋出一個TypeError異常。
3、hasattr(object,name):測試一個對象是否有指定的屬性
4、getattr(object, name[, default]):返回對象指定的屬性值
5、setattr(object,name,value):設置指定屬性的值
6、delattr(object,name):刪除對象中指定的屬性,如果屬性不存在拋出異常。
還有一個屬性函數,property
下表列出了可以在自己的類中覆蓋的一些通用方法

給個題目大家看下:
請在類中定義一個變量,用於跟蹤該類有多少個實例被創建(實例化一個對象時,變量+1,銷毀一個對象時,變量自動-1)
代碼如下;
class A: count = 0 def __init__(self): A.count += 1 def __del__(self): A.count -= 1

