Python面向?qū)ο?/h1>

今天要學(xué)習(xí)的是面向?qū)ο笈哐欤琍ython從設(shè)計之初就已經(jīng)是一門面向?qū)ο蟮恼Z言旁涤,正因為如此碉咆,在Python中創(chuàng)建一個類和對象是很容易的,我們先一起來看一下類和對象的定義~

類和對象的定義

class 類的名稱:
    語句塊

# 舉例說明
class Student:
    num = 100
    def showNum(self):
        return 200

print(Student.num)       # 輸出:100
print(Student.showNum)
# 輸出:<function Student.showNum at 0x009A9468>

# Student就是類對象败玉,num是類變量敌土,showNum是方法镜硕,self為類對象的實(shí)例, 類名稱一般需要大寫
  • :用來描述具有相同的屬性和方法的對象的集合返干;

  • 對象:通過類定義的數(shù)據(jù)結(jié)構(gòu)實(shí)例谦疾;

  • 簡單來說就是在python中,用屬性表示特征犬金,用方法表示技能念恍,因而具有相同特征和技能的一類事物就是‘類’,對象是則是這一類事物中具體的一個晚顷;

實(shí)例的定義

講完類和對象峰伙,我們來看一下實(shí)例,類是抽象的模板该默,而實(shí)例是根據(jù)類創(chuàng)建出來的一個個具體的“對象”瞳氓,每個對象都擁有相同的方法,但各自的屬性可能不同栓袖;

class Student:
    def prt(self):
        print(self)
        print(self.__class__)

s = Student()
s.prt()

# 執(zhí)行結(jié)果:
# <__main__.Student object at 0x0000000001D7CDA0>
# <class '__main__.Student'>

上述例子中self代表的是類的實(shí)例匣摘,而self.__class__指向類,且self 不是 python 關(guān)鍵字裹刮,我們把self換成其它的單詞也可以正常運(yùn)行音榜;

什么是實(shí)例化

我們知道了什么是實(shí)例,那實(shí)例化又是什么呢捧弃,接著看下面這個例子赠叼,在Student類中有兩個方法,一個是初始化方法__init__违霞,另一個是我自己定義的方法showClass()方法

class Student:
    num = 100
    def __init__(self):
        self.name = '張三'
    def show(self):
        return '李四'

print(Student.num)         # 輸出:100
print(Student.show)
輸出:<function Student.show at 0x0000000002765BF8>

stu = Student()
# 這就是實(shí)例化嘴办,且實(shí)例化會自定調(diào)用__init__方法,self會自動傳遞买鸽,不能有return返回值

print(stu.name)            # 張三

  • 類名加括號就是實(shí)例化涧郊,實(shí)例化會自動調(diào)用__init__()方法,可以用它來為每個實(shí)例定制自己的特征(屬性)眼五;

  • init()方法被稱為類的構(gòu)造函數(shù)或初始化方法妆艘,需要注意的是__init__()方法不能有return返回值;

類變量和實(shí)例變量

然后我們來講一下什么是類變量和實(shí)例變量,看看這兩者之間有什么不同啼肩;

# 實(shí)例變量是實(shí)例特有的,類變量是類和實(shí)例共有的
class Student:
    num = 100
    def __init__(self, name):
        self.name = name

    def showClass(self):
        return 200

print(Student.num)
print(Student.showClass)

stu = Student('張三') # 實(shí)例化,會調(diào)用__init__方法劳淆,self會自動傳遞,不能有return返回值

print(stu.name) # 實(shí)例變量
print(stu.num) # 類變量

直接看這個實(shí)例可能還不太直觀,大家自己在程序里面動手運(yùn)行一下,使用Student類調(diào)用num和name兩個變量逗物,就會發(fā)現(xiàn)在調(diào)用num的時候能正常輸出,而調(diào)用name的時候報錯了瑟俭。然后再用實(shí)例對象stu調(diào)用這兩個變量試試翎卓,我們就能得出下面兩個結(jié)論:

  • 類變量:類變量在整個實(shí)例化的對象中是公用的,也就是定義在類中且在函數(shù)體之外的變量(但類變量通常不作為實(shí)例變量使用)摆寄;

  • 實(shí)例變量:在類的聲明中失暴,屬性是用變量來表示的,這種變量就稱為實(shí)例變量微饥,是定義在類里面的方法中的變量逗扒;

類方法和實(shí)例方法

講完了類變量和實(shí)例變量,那我們來看一下類方法和實(shí)例方法:

class Student:
    num = 100
    def __init__(self, name):
        self.name = name
    def showClass(self):
        return '張三'

    @classmethod
    def add(cls):
        print(cls)

stu = Student('張三')    # 實(shí)例化欠橘,會調(diào)用__init__方法矩肩,self會自動傳遞,不能有return返回值
print(stu.name)          # 實(shí)例變量 輸出:張三
print(stu.num)           # 類變量  輸出: 100

print(stu.__dict__)     # 類的屬性保存在自己的字典中肃续,包括類變量和方法
print(stu.__dict__)     # 實(shí)例的屬性保存在自己的字典中黍檩,包括實(shí)例的變量

stu.add()              # 類方法可以被實(shí)例對象調(diào)用  輸出:<class '__main__.Student'>
stu.__class__.add()

print(Student.showClass())     # 報錯,實(shí)例方法不可以被類對象調(diào)用
print(Student.name)            # 實(shí)例可以訪問類的屬性始锚,類無法訪問實(shí)例的屬性

我們動手試一下刽酱,分別用Student類,和實(shí)例對象stu來調(diào)用類方法和實(shí)例方法瞧捌,我們就能得出一下結(jié)論:

  • 類方法使用裝飾器@classmethod肛跌,第一個參數(shù)必須是當(dāng)前類對象,該參數(shù)名一般約定為“cls”察郁,通過它來傳遞類的屬性和方法(不能傳實(shí)例的屬性和方法)衍慎;

  • 類方法可以被實(shí)例對象和類對象調(diào)用;

  • 實(shí)例方法第一個參數(shù)必須是實(shí)例對象皮钠,該參數(shù)名一般約定為“self”稳捆,通過它來傳遞實(shí)例的屬性和方法(也可以傳類的屬性和方法);

  • 實(shí)例方法只能由實(shí)例對象調(diào)用麦轰;

靜態(tài)方法

除了類方法和實(shí)例方法之外乔夯,還有一個方法叫做靜態(tài)方法,我們一起來看一下靜態(tài)方法如何使用:

class Student:
    def __init__(self, name):
        self.name = name

    @staticmethod
    def sub():
        print('static')

stu = Student('李四')

stu.sub()
# 實(shí)例可以調(diào)用靜態(tài)方法    輸出:static

Student.sub()
# 類可以調(diào)用靜態(tài)方法  輸出:static

然后我們可以得出一下兩個結(jié)論:

  • 靜態(tài)方法使用裝飾器@staticmethod款侵,參數(shù)隨意末荐,沒有“self”和“cls”參數(shù),但是方法體中不能使用類或?qū)嵗娜魏螌傩院头椒ǎ?/p>

  • 靜態(tài)方法可以被實(shí)例對象和類對象調(diào)用新锈;

私有屬性和保護(hù)屬性

  • 兩個下劃線__開頭的屬性為私有屬性甲脏,不能在類的外部被使用或直接訪問;

  • 一個下劃線_開頭的為保護(hù)屬性,只有類實(shí)例和子類實(shí)例能訪問块请,需通過類提供的接口進(jìn)行訪問娜氏;

我們來看一下私有屬性和保護(hù)屬性是如何使用的:

class Student(object):
    def __init__(self):
        self.__private_field = 200    # private
        self._protect_field = 200    # protect

stu = Student()
# print(stu.__private_field)  # 報錯,實(shí)例對象不可以調(diào)用私有屬性
print(stu._protect_field)   # 輸出:200

屬性裝飾器

  • 第一種寫法:使用@property裝飾器墩新,將類的方法變?yōu)閷傩裕?/li>

class Student:
    num = 100
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @name.deleter
    def name(self):
        del self.__name

stu = Student('張三')
print(stu.name)     # 輸出:張三

stu.name = '李四'
print(stu.name)     # 輸出:李四 

  • 第二種寫法:使用屬性函數(shù)property()贸弥,直接把方法當(dāng)屬性來操作;
class Student:
    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self, value):
        self.__name = value

    def del_name(self):
        del self.__name
        print('實(shí)例的屬性被刪除了')

    # 這里表示property是用來修飾name這個屬性的
    name = property(fget=get_name, fset=set_name, fdel=del_name, doc='hello')

stu = Student('張三')
print(stu.name)    # 張三

stu.name = '李四'  # 給name賦值
print(stu.name)   # 李四
  • 一個property對象包含三個方法:getter, setter, deleter海渊,當(dāng)一個函數(shù)被@property裝飾器修飾時绵疲,系統(tǒng)會自動創(chuàng)建一個包含對應(yīng)訪問函數(shù)的同名屬性;

類的繼承

class Animal:
    def __init__(self):
        self.type = 'animals'
    def eat(self):
        print('{} 吃臣疑,Animal類中'.format(self.__class__.__name__))   # Animal 吃最岗,Animal類中

class Person(Animal):
    def talk(self):
        print('講話')

# animal = Animal()
# animal.eat()
# 
# print(animal.type)  # animals
# animal.talk()       # 報錯,父類不可以調(diào)用子類的方法

person = Person()
print(person.type)  # animals

# Person調(diào)用Animal類的eat方法
person.eat()       # 輸出:Person 吃朝捆,Animal類中
person.talk()      # 講話
  • 繼承是一種創(chuàng)建類的方法般渡,一個類可以繼承來自一個或多個父類,原始類稱為基類或超類芙盘;

  • 繼承可以很方便的幫助子類擁有父類的屬性和方法驯用,減少代碼冗余,子類可以定義自己的方法和屬性儒老,也可以覆蓋父類的方法和屬性蝴乔;

  • 實(shí)現(xiàn)繼承:指使用基類的屬性和方法而無需額外編碼的能力;

  • 接口繼承:指僅使用屬性和方法的名稱驮樊、但是子類必須提供實(shí)現(xiàn)的能力(子類重構(gòu)父類方法)薇正;

屬性查找順序

class Animal:
    __name = 'animal'
    def __init__(self):
        self.type = 'animal'
    def eat(self):
        print('{} eat'.format(self.__class__.__name__))

class Person(Animal):
    def talk(self):
        print('talk')

person = Person()
print(person.__name)   # 子類不能訪問 父類的私有屬性

  • 父類的私有屬性無法被子類訪問;

  • 屬性的查找順序:先從對象自身的__dict__中查找->然后從對象所在類的__dict__中查找->然后從父類的__dict__中查找囚衔,直至找到或者報錯沒有找到挖腰;

方法重寫

  • 子類可以覆蓋父類的方法,可以在覆蓋的方法中調(diào)用父類的方法练湿,且父類的類方法猴仑,靜態(tài)方法也可以被覆蓋
class Animal:
    def __init__(self):
        self.type = 'animal'

    def eat(self):
        print('{} eat'.format(self.__class__.__name__))

class Person(Animal):
    def eat(self):
        print('洗手')  # 洗手
        print('{} eat'.format(self.__class__.__name__))  # Person eat
        super().eat()  # 調(diào)用父類的方法                    # Person eat
        # super(Person, self).eat()   等價于 super().eat()

person = Person()
person.eat()
  • 繼承中的init方法
class Animal:
    def __init__(self):
        self.one = 'one'

class Person(Animal):
    def __init__(self):
        self.two = 'two'
        self.three = 'three'

    def show(self):
        print(self.one, self.two, self.three)

person = Person()
print(person.__dict__)  # 輸出:{'two': 'two', 'three': 'three'}
person.show()    # 報錯,person沒有one這個屬性
print(person.one)  #同樣報錯
  • 代碼修改肥哎,如果父類有init方法辽俗,且子類也有init方法,最好在子類的init方法中手動調(diào)用父類的init方法
class Animal:
    def __init__(self):
        self.one = 'one'

class Person(Animal):
    def __init__(self):
        self.two = 'two'
        self.three = 'three'
        super().__init__()  # 繼承父類的__init__方法篡诽,且父類init方法的調(diào)用寫在子類的什么地方也有講究

    def show(self):
        print(self.one, self.two, self.three)

person = Person()
print(person.__dict__)
print(person.one)
# 輸出:one  崖飘,因為繼承了父類的init__方法,所以可以訪問one屬性
  • 如果你的父類方法的功能不能滿足你的需求杈女,就可以在子類重寫你父類的方法朱浴;

  • 子類可以覆蓋父類的方法吊圾,且可以在覆蓋的方法中調(diào)用父類的方法;

  • super()函數(shù)是用于調(diào)用父類(超類)的一個方法赊琳, Python 3 可以使用直接使用super().xxx 代替 super(Class, self).xxx

裝飾器

  • 裝飾器是一個很著名的設(shè)計模式砰碴,經(jīng)常被用于有切面需求的場景躏筏,較為經(jīng)典的有插入日志、性能測試呈枉、事務(wù)處理等趁尼;

  • python裝飾器本質(zhì)上就是一個函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外的功能猖辫,裝飾器的返回值也是一個函數(shù)對象(函數(shù)的指針)酥泞;

  • 概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能啃憎,也稱之為擴(kuò)展功能芝囤;

Mixin

  • Mixin是一種設(shè)計模式,通過多繼承的方式對類的功能進(jìn)行增強(qiáng)辛萍;

  • Mixin可以在不修改任何源代碼的情況下悯姊,對已有類進(jìn)行擴(kuò)展;

  • 可以根據(jù)需要使用已有的功能進(jìn)行組合贩毕,來實(shí)現(xiàn)“新”類悯许;

  • 還能很好的避免類繼承的局限性,因為新的業(yè)務(wù)需要可能就需要創(chuàng)建新的子類辉阶;

Mixin類的注意點(diǎn)

  • 在Mixin類中先壕,不能寫初始化的__init__方法,因為Mixin類不做為獨(dú)立類使用谆甜;

  • Mixin類原則上必須作為其他類的基類垃僚,實(shí)現(xiàn)其他類的功能增強(qiáng);

  • Mixin類的基類必須也是Mixin類规辱;

  • 使用Mixin方式增強(qiáng)功能的的類冈在,必須將Mixin類寫在繼承列表的第一個位置;

  • Mixin比decorator更加強(qiáng)大按摘;

參考:https://www.9xkd.com/user/plan-view.html?id=1853344716

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末包券,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子炫贤,更是在濱河造成了極大的恐慌溅固,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兰珍,死亡現(xiàn)場離奇詭異侍郭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門亮元,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猛计,“玉大人,你說我怎么就攤上這事爆捞》盍觯” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵煮甥,是天一觀的道長盗温。 經(jīng)常有香客問我,道長成肘,這世上最難降的妖魔是什么卖局? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮双霍,結(jié)果婚禮上砚偶,老公的妹妹穿的比我還像新娘。我一直安慰自己洒闸,他們只是感情好蟹演,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著顷蟀,像睡著了一般酒请。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸣个,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天羞反,我揣著相機(jī)與錄音,去河邊找鬼囤萤。 笑死昼窗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涛舍。 我是一名探鬼主播澄惊,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼富雅!你這毒婦竟也來了掸驱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤没佑,失蹤者是張志新(化名)和其女友劉穎毕贼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛤奢,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鬼癣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年陶贼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片待秃。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡拜秧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出章郁,到底是詐尸還是另有隱情枉氮,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布驱犹,位于F島的核電站嘲恍,受9級特大地震影響足画,放射性物質(zhì)發(fā)生泄漏雄驹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一淹辞、第九天 我趴在偏房一處隱蔽的房頂上張望医舆。 院中可真熱鬧,春花似錦象缀、人聲如沸蔬将。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霞怀。三九已至,卻和暖如春莉给,著一層夾襖步出監(jiān)牢的瞬間毙石,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工颓遏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留徐矩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓叁幢,卻偏偏與公主長得像滤灯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子曼玩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容