Python基础入门_5面向对象基础
Python 基礎(chǔ)入門前四篇:
- Python 基礎(chǔ)入門–簡(jiǎn)介和環(huán)境配置
- Python基礎(chǔ)入門_2基礎(chǔ)語(yǔ)法和變量類型
- Python基礎(chǔ)入門_3條件語(yǔ)句和迭代循環(huán)
- Python基礎(chǔ)入門_4函數(shù)
第五篇主要介紹 Python 的面向?qū)ο蠡A(chǔ)知識(shí),也就是類的介紹,包括類方法和屬性、構(gòu)造方法、方法重寫、繼承等,最后給出兩道簡(jiǎn)單的練習(xí)題。
5.面向?qū)ο?/h3> 
5.1 簡(jiǎn)介
 
先簡(jiǎn)單介紹一些名詞概念。
- 類:用來(lái)描述具有相同的屬性和方法的對(duì)象的集合。它定義了該集合中每個(gè)對(duì)象所共有的屬性和方法。對(duì)象是類的實(shí)例。
- 類方法:類中定義的函數(shù)。
- 類變量:類變量在整個(gè)實(shí)例化的對(duì)象中是公用的。類變量定義在類中且在函數(shù)體之外。類變量通常不作為實(shí)例變量使用。
- 數(shù)據(jù)成員:類變量或者實(shí)例變量用于處理類及其實(shí)例對(duì)象的相關(guān)的數(shù)據(jù)。
- 方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對(duì)其進(jìn)行改寫,這個(gè)過(guò)程叫方法的覆蓋(override),也稱為方法的重寫。
- 局部變量:定義在方法中的變量,只作用于當(dāng)前實(shí)例的類。
- 實(shí)例變量:在類的聲明中,屬性是用變量來(lái)表示的。這種變量就稱為實(shí)例變量,是在類聲明的內(nèi)部但是在類的其他成員方法之外聲明的。
- 繼承:即一個(gè)派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個(gè)派生類的對(duì)象作為一個(gè)基類對(duì)象對(duì)待。例如,有這樣一個(gè)設(shè)計(jì):一個(gè) Dog 類型的對(duì)象派生自 Animal 類,這是模擬"是一個(gè)(is-a)"關(guān)系(例圖,Dog 是一個(gè) Animal)。
- 實(shí)例化:創(chuàng)建一個(gè)類的實(shí)例,類的具體對(duì)象。
- 對(duì)象:通過(guò)類定義的數(shù)據(jù)結(jié)構(gòu)實(shí)例。對(duì)象包括兩個(gè)數(shù)據(jù)成員(類變量和實(shí)例變量)和方法。
Python中的類提供了面向?qū)ο缶幊痰乃谢竟δ?#xff1a;類的繼承機(jī)制允許多個(gè)基類,派生類可以覆蓋基類中的任何方法,方法中可以調(diào)用基類中的同名方法。
對(duì)象可以包含任意數(shù)量和類型的數(shù)據(jù)。
5.2 類定義
下面是簡(jiǎn)單定義一個(gè)類:
# 定義一個(gè)動(dòng)物類別 class Animal(object):# 類變量eat = Truedef __init__(self, name, gender):self.name = nameself.gender = gender# 類方法def run(self):return 'Animal run!' # 實(shí)例化類 anm = Animal('animal', 'male')# 訪問(wèn)類的屬性和方法 print("Animal 類的屬性 eat 為:", anm.eat) print("Animal 類的方法 run 輸出為:", anm.run())輸出結(jié)果:
Animal 類的屬性 eat 為: True Animal 類的方法 run 輸出為: Animal run!上述是一個(gè)簡(jiǎn)單的類的定義,通常一個(gè)類需要有關(guān)鍵字 class ,然后接一個(gè)類的名字,然后如果是 python2.7 是需要如例子所示加上圓括號(hào)和 object ,但在 python3 版本中,其實(shí)可以直接如下所示:
class Animal:構(gòu)造方法和特殊參數(shù) self 的表示
然后 __init__ 是構(gòu)造方法,即在進(jìn)行類實(shí)例化的時(shí)候會(huì)調(diào)用該方法,也就是 anm = Animal('animal', 'male')。
此外,對(duì)于類的方法,第一個(gè)參數(shù)也是必須帶上的參數(shù),按照慣例名稱是 self ,它代表的是類的實(shí)例,也就是指向?qū)嵗旧淼囊?#xff0c;讓實(shí)例本身可以訪問(wèn)類中的屬性和方法。如下代碼所示:
class Test:def prt(self):print(self)print(self.__class__)t = Test() t.prt()輸出結(jié)果:
<__main__.Test object at 0x000002A262E2BA20> <class '__main__.Test'>可以看到 print(self) 的結(jié)果是輸出當(dāng)前對(duì)象的地址,而 self.__class__ 表示的就是類。
剛剛說(shuō)了 self 只是慣例取的名稱,換成其他名稱也可以,如下所示:
# 不用 self 名稱 class Test2:def prt(sss):print(sss)print(sss.__class__)t2 = Test2() t2.prt()輸出結(jié)果是一樣的,類實(shí)例的地址改變了而已。
<__main__.Test2 object at 0x000001FB7644BBA8> <class '__main__.Test2'>類方法
類方法和構(gòu)造方法一樣,首先是關(guān)鍵字 def ,接著就是參數(shù)第一個(gè)必須是 self ,表示類實(shí)例的參數(shù)。
#類定義 class people:#定義基本屬性name = ''age = 0#定義私有屬性,私有屬性在類外部無(wú)法直接進(jìn)行訪問(wèn)__weight = 0#定義構(gòu)造方法def __init__(self,n,a,w):self.name = nself.age = aself.__weight = wdef speak(self):print("%s 說(shuō): 我 %d 歲。" %(self.name,self.age))# 實(shí)例化類 p = people('runoob',10,30) p.speak()輸出結(jié)果
runoob 說(shuō): 我 10 歲。5.3 繼承
繼承的語(yǔ)法定義如下:
class DerivedClassName(BaseClassName1,BaseClassName2,...):<statement-1>...<statement-N>需要注意:
- 圓括號(hào)中基類的順序,當(dāng)基類含有相同方法名,子類沒(méi)有指定(即類似 BaseClass1.method1()),python 會(huì)從左到右搜索繼承的基類是否包含該方法;
- 基類和子類必須定義在一個(gè)作用域內(nèi);
下面給出一個(gè)代碼例子,基類定義還是上一節(jié)中的 people 類別,這次定義一個(gè)子類 student
# 單繼承示例 class student(people):grade = ''def __init__(self, n, a, w, g):# 調(diào)用父類的構(gòu)造方法people.__init__(self, n, a, w)self.grade = g# 覆寫父類的方法def speak(self):print("%s 說(shuō): 我 %d 歲了,我在讀 %d 年級(jí)" % (self.name, self.age, self.grade))s = student('ken', 10, 60, 3) s.speak()輸出結(jié)果
ken 說(shuō): 我 10 歲了,我在讀 3 年級(jí)這是一個(gè)單繼承,即繼承一個(gè)基類的示例,子類的構(gòu)造方法必須先調(diào)用基類(父類)的構(gòu)造方法:
# 調(diào)用父類的構(gòu)造方法 people.__init__(self, n, a, w)另一種調(diào)用基類的構(gòu)造方法,利用 super() 函數(shù):
super.__init__(self, n, a, w)方法重寫
上述例子還重寫了基類的方法 speak()。
方法重寫是在基類的方法無(wú)法滿足子類的需求時(shí),在子類重寫父類的方法。
多繼承
python 也支持多繼承,下面是一個(gè)例子,繼續(xù)沿用剛剛定義的一個(gè)類 student ,然后再重新定義一個(gè)基類 speaker
#另一個(gè)類,多重繼承之前的準(zhǔn)備 class speaker():topic = ''name = ''def __init__(self,n,t):self.name = nself.topic = tdef speak(self):print("我叫 %s,我是一個(gè)演說(shuō)家,我演講的主題是 %s"%(self.name,self.topic))#多重繼承 class sample(speaker,student):a =''def __init__(self,n,a,w,g,t):student.__init__(self,n,a,w,g)speaker.__init__(self,n,t)test = sample("Tim",25,80,4,"Python") test.speak() #方法名同,默認(rèn)調(diào)用的是在括號(hào)中排前地父類的方法輸出結(jié)果:
我叫 Tim,我是一個(gè)演說(shuō)家,我演講的主題是 Python而如果想指定任意父類的方法,可以添加下面這段代碼:
# 顯示調(diào)用 student 父類的 speak 方法 def speak(self):super(student, self).speak()上面介紹過(guò)了, super() 函數(shù)是調(diào)用父類的一個(gè)方法,可以直接 super().method() ,但如果是多繼承并且指定父類的話,就如上述所示,添加父類名字以及 self 來(lái)表示類實(shí)例。
另外,python2.7 調(diào)用 super() 方法,也需要傳入父類名字和 self 兩個(gè)參數(shù)。
5.4 類屬性與方法
屬性和方法的訪問(wèn)權(quán)限,即可見(jiàn)性,有三種,公開、受保護(hù)以及私有,私有方法和私有屬性如下定義:
-  類的私有屬性:兩個(gè)下劃線開頭,聲明該屬性私有,不能在類的外部被使用或直接訪問(wèn),而在類內(nèi)部的方法中使用時(shí):self.__private_attrs 
-  類的私有方法:兩個(gè)下劃線開頭,聲明該方法為私有方法,只能在類的內(nèi)部調(diào)用 ,不能在類的外部調(diào)用。self.__private_methods。 
而如果是受保護(hù)的屬性或者方法,則是一個(gè)下劃線開頭,例如 _protected_attr 。
下面是一個(gè)簡(jiǎn)單的示例:
class JustCounter:__secretCount = 0 # 私有變量publicCount = 0 # 公開變量def count(self):self.__secretCount += 1self.publicCount += 1print(self.__secretCount)self.__count()def __count(self):print('私有方法')counter = JustCounter() counter.count() counter.count() print(counter.publicCount) print(counter.__secretCount) # 報(bào)錯(cuò),實(shí)例不能訪問(wèn)私有變量 print(counter.__count())輸出結(jié)果
1 私有方法 2 私有方法 2調(diào)用私有屬性會(huì)報(bào)錯(cuò):
AttributeError: 'JustCounter' object has no attribute '__secretCount'調(diào)用私有方法會(huì)報(bào)錯(cuò):
AttributeError: 'JustCounter' object has no attribute '__count'類的屬性不僅可以是變量,也可以是類實(shí)例作為一個(gè)屬性,例子如下所示:
class TimeCounter:def __init__(self):print('timer')class JustCounter:__secretCount = 0 # 私有變量publicCount = 0 # 公開變量def __init__(self):self.timer = TimeCounter()def count(self):self.__secretCount += 1self.publicCount += 1print(self.__secretCount)self.__count()def __count(self):print('私有方法')counter = JustCounter() counter.count() counter.count() print(counter.publicCount)同樣繼續(xù)采用 JustCounter 類,只是新定義 TimeCounter ,并在 JustCounter 調(diào)用構(gòu)造方法,實(shí)例化一個(gè) TimeCounter 類,輸出結(jié)果:
timer 1 私有方法 2 私有方法 25.5 練習(xí)
最后是來(lái)自 Python-100-Days–Day08面向?qū)ο蠡A(chǔ) 的兩道練習(xí)題:
定義一個(gè)簡(jiǎn)單的數(shù)字時(shí)鐘
這個(gè)例子將采用受保護(hù)的屬性,即屬性名字以單下劃線開頭,所以初始化的構(gòu)造方法如下:
from time import sleepclass Clock(object):"""數(shù)字時(shí)鐘"""def __init__(self, hour=0, minute=0, second=0):'''初始化三個(gè)基本屬性,時(shí),分,秒:param hour::param minute::param second:'''self._hour = hourself._minute = minuteself._second = second然后是模擬時(shí)鐘的運(yùn)行,這里只需要注意時(shí)鐘運(yùn)行過(guò)程邊界問(wèn)題,即秒和分都是每到 60 需要置零,并讓分或者時(shí)加 1,而時(shí)是每隔 24 需要進(jìn)行這樣的操作
def run(self):'''模擬時(shí)鐘的運(yùn)行:return:'''self._second += 1if self._second == 60:self._second = 0self._minute += 1if self._minute == 60:self._minute = 0self._hour += 1if self._hour == 24:self._hour = 0最后是顯示時(shí)間,需要注意時(shí)、分和秒三個(gè)屬性都是整數(shù),如果采用 % 進(jìn)行格式化,需要調(diào)用 str() 方法顯示將它們從整數(shù)變成字符串類型,而如果用 format() 方法,就不需要。
def show(self):'''顯示時(shí)間:return:'''print("{:02d}:{:02d}:{:02d}".format(self._hour, self._minute, self._second))簡(jiǎn)單的運(yùn)用例子,這里調(diào)用 time.sleep() 方法,每顯示一次時(shí)間休眠一秒,然后運(yùn)行,設(shè)置循環(huán)次數(shù)是 5 次。
# 簡(jiǎn)單時(shí)鐘例子 clock = Clock(23, 59, 57) i = 0 while i < 5:clock.show()sleep(1)clock.run()i += 1輸出結(jié)果:
23:59:57 23:59:58 23:59:59 00:00:00 00:00:01定義一個(gè)類描述點(diǎn)之間的移動(dòng)和距離
第二個(gè)練習(xí)是定義一個(gè)類,描述平面上點(diǎn)之間的移動(dòng)和距離計(jì)算
首先是基本的構(gòu)造方法定義,這里作為平面上的點(diǎn),需要定義的屬性就是點(diǎn)的橫縱坐標(biāo):
# 定義描述平面上點(diǎn)之間的移動(dòng)和計(jì)算距離的類 class Point(object):def __init__(self, x=0, y=0):'''初始的坐標(biāo):param x:橫坐標(biāo):param y:縱坐標(biāo)'''self._x = xself._y = y接著,點(diǎn)的移動(dòng),可以有兩種實(shí)現(xiàn),第一種直接說(shuō)明目標(biāo)點(diǎn)的坐標(biāo):
def move_to(self, new_x, new_y):'''移動(dòng)到新的坐標(biāo):param new_x:新的橫坐標(biāo):param new_y:新的縱坐標(biāo):return:'''self._x = new_xself._y = new_y第二種則是只告訴分別在橫、縱兩個(gè)方向移動(dòng)的距離:
def move_by(self, dx, dy):'''移動(dòng)指定的增量:param dx:橫坐標(biāo)的增量:param dy:縱坐標(biāo)的增量:return:'''self._x += dxself._y += dy然后計(jì)算點(diǎn)之間的距離方法,這里就需要用到剛剛從 math 庫(kù)導(dǎo)入的方法 sqrt ,即求取平方根:
def distance(self, other):'''計(jì)算與另一個(gè)點(diǎn)的距離:param other::return:'''x_dist = self._x - other._xy_dist = self._y - other._yreturn sqrt(x_dist ** 2 + y_dist ** 2)最后當(dāng)然就是打印當(dāng)前點(diǎn)的坐標(biāo)信息了:
def __str__(self):'''顯示當(dāng)前點(diǎn)坐標(biāo):return:'''return '({},{})'.format(self._x, self._y)簡(jiǎn)單的應(yīng)用例子
p1 = Point(10, 20) p2 = Point(30, 5) print('point1:', p1) print('point2:', p2) p1.move_to(15, 25) print('after move to (15, 25), point1:', p1) p1.move_by(20, 10) print('move by (20, 10), point1:', p1) dist = p1.distance(p2) print('distance between p1 and p2: ', dist)輸出結(jié)果:
point1: (10,20) point2: (30,5) after move to (15, 25), point1: (15,25) move by (20, 10), point1: (35,35) distance between p1 and p2: 30.4138126514911參考:
- 《Python 編程從入門到實(shí)踐》
- Python3 面向?qū)ο?/li>
- Python-100-Days–Day08面向?qū)ο蠡A(chǔ)
小結(jié)
本文簡(jiǎn)單介紹 Python 面向?qū)ο蟮幕A(chǔ)內(nèi)容,主要是類的定義、方法和屬性介紹,繼承和方法重寫,這些是比較基礎(chǔ)的內(nèi)容,后續(xù)計(jì)劃的進(jìn)階內(nèi)容關(guān)于面向?qū)ο蟛糠?#xff0c;還會(huì)繼續(xù)介紹如多態(tài)、裝飾器等內(nèi)容。
此外,本文的代碼都上傳到我的 github 上了:
https://github.com/ccc013/Python_Notes/blob/master/Practise/class_example.py
歡迎關(guān)注我的微信公眾號(hào)–機(jī)器學(xué)習(xí)與計(jì)算機(jī)視覺(jué),或者掃描下方的二維碼,大家一起交流,學(xué)習(xí)和進(jìn)步!
總結(jié)
以上是生活随笔為你收集整理的Python基础入门_5面向对象基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: 收集19个前端开发人员的必备工具
- 下一篇: 硬件:关于CPU超频知识笔记
