欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python面向?qū)ο笕筇卣鳎豪^承、封裝和多態(tài)的深度解析

 更新時間:2025年01月11日 09:31:08   作者:小劉042  
在面向?qū)ο蟪绦蛟O(shè)計中,對象可以看做是數(shù)據(jù)(特性)以及由一系列可以存取、操作這些數(shù)據(jù)的方法所組成的集合,Python是面向?qū)ο蟮恼Z言,支持面向?qū)ο缶幊痰娜筇匦裕豪^承、封裝(隱藏)、多態(tài),本文將逐一講解Python的三大特性

在面向?qū)ο蟪绦蛟O(shè)計中,對象可以看做是數(shù)據(jù)(特性)以及由一系列可以存取、操作這些數(shù)據(jù)的方法所組成的集合。Python是面向?qū)ο蟮恼Z言,支持面向?qū)ο缶幊痰娜筇匦裕豪^承、封裝(隱藏)、多態(tài),本文將逐一講解Python的三大特性。

封裝

繼承的基本概念以及使用

封裝的概念:隱藏內(nèi)部實現(xiàn)的細節(jié),只對外提供操作方法(接口)。這個概念我們在上一小節(jié)中也已經(jīng)學(xué)習過了,我們主要是去了解其在代碼中是如何去實現(xiàn)的:通過有著類似 訪問修飾限定符 功能的下劃線來實現(xiàn)。

權(quán)限控制:通過對屬性或方法添加單下劃線、雙下劃線以及首尾雙下劃線來實現(xiàn)。

下劃線種類

功能

單下劃線開頭

表示protected,受保護的成員,這類成員被視為僅供內(nèi)部家族使用,允許類本身和子類進行訪問,但實際上它可以被外部代碼訪問

雙下劃線開頭

表示private,私有的成員,這類成員只允許定義該屬性或方法的類本身進行訪問

首尾雙下劃線

一般表示特殊的方法

代碼演示:

class Dog():
    # 首尾雙線劃線 ——> 特殊方法
    def __init__(self, name, age):
        # 雙下劃線開頭 ——> private修飾,只能在類內(nèi)訪問
        self.__name = name
        # 單下劃線開頭 ——> protected修飾,在類內(nèi)與子類才能訪問
        self._age = age
 
    # 單下劃線開頭 ——> protected修飾,在類內(nèi)與子類才能訪問
    def _fun1(self):
        print('這是被protected所修飾的方法')
    # 雙下劃線開頭 ——> private修飾,在類內(nèi)才能訪問
    def __fun2(self):
        print('這是被private所修飾的方法')
 
# 這里是類外了
dog = Dog('小劉', 18)
print(dog._age)
# print(dog.__name)
dog._fun1()
# dog.__fun2()
# 和上面一樣,直接去訪問的話,就會報錯,
# 但是我們可以使用 對象.__dir()__ 或者 dir(對象) 先去查看所有的屬性與方法
# 然后通過其中的"屬性"與"方法名"去調(diào)用真正的屬性與方法
# print(dog.__dir__())
# print(dir(dog))
 
print(dog._Dog__name)
dog._Dog__fun2()

運行結(jié)果:

Python初始 - 面向?qū)ο笕筇卣鱛下劃線

根據(jù)上面的訪問方式,我們可以推測出:被 protected、private 所修飾 方法 與 屬性只是在類中對應(yīng)的名稱發(fā)生了變化,而我們不知道,但是可以通過特殊手段知曉,從而繼續(xù)訪問。

但是上面的方式不是很推薦,類似與 Java中的反射機制了,有點反常規(guī)。除了上面這種方式,Python還提供了兩種方式來實現(xiàn)訪問 與 修改 私有是屬性與方法。

1、在 私有的方法 或者 屬性上,進行套殼處理。

2、在1的基礎(chǔ)上,通過 @property 裝飾器 來修飾方法,使其變?yōu)閷傩?,就變?yōu)樵L問與修改屬性了,最終也會變的很簡單。

代碼演示:

class Dog():
    def __init__(self, name, age):
        self.__name = name
        self.age = age
 
    # 如果想要去訪問除了,使用dir()之外,還有兩種方式:
 
    # 使用實例方法去間接訪問與修改
    def get_name(self):
        return self.__name
    def set_name(self, name):
        self.__name = name
 
    # 使用@property裝飾器,將方法轉(zhuǎn)為屬性使用
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self, name):
        self.__name = name
 
dog = Dog('老劉', 8)
# 1、通過實例方法的形式去使用
print(dog.get_name())
dog.set_name('小劉')
print('='*18)
# 2、通過@property裝飾器,將方法轉(zhuǎn)為屬性
print(dog.name)
dog.name = '老劉' # 修改屬性的樣式,去傳參
print(dog._Dog__name)
print('='*18)
dog._Dog__name = '小劉'
print(dog._Dog__name)

運行結(jié)果:

Python初始 - 面向?qū)ο笕筇卣鱛父類_02

注意:我們在使用 @property 裝飾器,將屬性轉(zhuǎn)為方法時,取值的方法,必須被 @property 修飾,而修改值的方法,必須被 @取值方法名. setter修飾。

繼承

繼承的基本概念以及使用

繼承是指一個類(子類、派生類)繼承另一個類(父類、基類)的屬性與方法。

在Python中一個子類可以繼承N多個父類,這是與 Java決然不同的一點。Java屬于單繼承,而Python屬于多繼承,并且每個類都默認繼承自object類。當然,一個子類可以有多個父類,一個父類也可以有多個子類。

語法:

class 類名([父類列表]):

注意:當一個類的父類只有object類時,默認是可以不寫父類的,但是如果一個類有除object類之外的其他類,就需要將這些類全部寫到 () 中,當然這個()在只有繼承object類的情況下,也是可以不寫的,但是建議還是要寫上去。

代碼演示:

# 默認繼承object類,但是這個可以不寫
class Animal(object):
    def __init__(self, name, age, gender,sort):
        self.name = name
        self.age = age
        self.gender = gender
        self.__sort = sort
 
 
class Dog(Animal):
    pass
 
# 子類繼承父類,會將父類中除private修飾的方法與屬性全部拿過來
# 繼承了 __init__方法,以及 name、age、gender屬性
dog = Dog('小黑', 3, '雄', '哈士奇')
print(dog.name)
print(dog.age)
print(dog.gender)
# 同樣需要特殊手段才能訪問到
print(dog._Animal__sort)

運行結(jié)果:

Python初始 - 面向?qū)ο笕筇卣鱛子類_03

注意:我們在實例化一個對象時,會先去調(diào)用構(gòu)造方法(init 方法)給對象的屬性進行初始化賦值,如果一個類沒有構(gòu)造方法,但是由于這個類是默認繼承自object類,因此會調(diào)用object類中默認的 init 方法,但如果這個類繼承了其他類,就會先在其他類中去搜索這個方法,如果有則調(diào)用;反之,則還是去調(diào)用object類的。 而在上面的代碼中,Animal 類是有 init 方法,因此會去調(diào)用Animal 類的。

我們再看看多繼承的代碼:

class Person():
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
    def show(self):
        print(f'我叫{self.name},今年{self.age},性別是{self.gender}')
 
class Father(Person):
    def __init__(self,name,age,gender):
        # 可以直接調(diào)用父類的初始化方法
        super().__init__(name,age,gender)
        # 下面這種方式是錯誤的
        # super().name = name
        # super().age = age
        # super().gender = gender
        # 下面的方式也行,但是不推薦
        # self.name = name
        # self.age = age
        # self.gender = gender
 
class Mother(Person):
    def __init__(self, name, age, gender):
        # 可以直接調(diào)用父類的初始化方法
        super().__init__(name, age, gender)
        # 下面這種方式是錯誤的
        # super().name = name
        # super().age = age
        # super().gender = gender
        # 下面的方式也行,但是不推薦
        # self.name = name
        # self.age = age
        # self.gender = gender
 
class Son(Father, Mother):
    def __init__(self, name, age, gender):
        # 可以直接調(diào)用父類的初始化方法
        super().__init__(name, age, gender)
        # 下面這種方式是錯誤的
        # super().name = name
        # super().age = age
        # super().gender = gender
        # 下面的方式也行,但是不推薦
        # self.name = name
        # self.age = age
        # self.gender = gender
 
father = Father('張三',25,'男')
mother = Mother('紅粉佳人',28,'女')
son = Son('趙四',29,'男')
 
father.show()
mother.show()
son.show()

運行結(jié)果:

Python初始 - 面向?qū)ο笕筇卣鱛下劃線_04

上面的代碼中,Son類、Mother類、Father類都是繼承自Person類的屬性與方法,它們是公用Person類的屬性與方法。

注意:上述 Son類繼承了多個父類,當我們?nèi)ナ褂?super().init 方法初始化子類對象時,默認是按照父類在Son()中的順序來查找的,這里是Father類定義聲明在前,因此這里調(diào)用的就是 Father 類的 init 方法,如果想要指定某個類的 init 方法的話,就需要使用 類名.init() 方法。例如:

# 這里的self代指當前Son類的實例對象
Mother.__init__(self,name,age,gender) # 可替換Son類中是super.init

方法重寫

當子類繼承父類時,子類就擁有了父類中的 公有成員、方法和受保護的成員、方法。如果我們對父類中有些成員不滿意的話,子類就可以重新定義成員。同理,方法也是如此,但是重新定義方法麻煩了,那有什么辦法呢?方法重寫,即 偷梁換柱,表面上這個方法還是原來的方法,但是其內(nèi)部實現(xiàn)的結(jié)構(gòu)早就發(fā)生變化了。

重寫的要求:方法名必須一樣,至于方法的返回值類型,參數(shù)列表、訪問權(quán)限這些可以不一樣。

代碼演示:

class Animal():
    def __init__(self,name,age):
        self.name = name
        self.age = age
 
    def eat(self):
        print(f'{self.name}正在吃狗糧,看小黑玩飛盤')
 
class Dog(Animal):
    def __init__(self,name,age):
        super().__init__(name,age)
    # 由于Animal類的eat方法只是隨便說在吃啥,并不具體,
    # 但我們想要打印出具體的食物,因此可以重寫(外殼不變,核心變化)
    def eat(self):
        print(f'{self.name}正在玩飛盤~')
 
class Cat(Animal):
    def __init__(self,name,age):
        super().__init__(name,age)
 
dog = Dog('小黑', 2)
# 子類重寫父類的方法之后,父類再去調(diào)用eat方法,就不再是調(diào)用父類的,而是自己的
dog.eat()
 
cat = Cat('小黃', 3)
# 子類沒有重寫父類的eat方法,因此還是去調(diào)用父類的eat方法
cat.eat()

運行結(jié)果:

Python初始 - 面向?qū)ο笕筇卣鱛父類_05

其實,重寫就是在子類中定義了一個與父類重名的方法,只不過因為 Python中語法的檢查不是很嚴格,因此這里就很容易不理解。

在Python中,我們就將重寫看作是子類定義了一個與父類重名的方法即可,在調(diào)用時,如果子類沒有這個方法,那么就是調(diào)用父類的同名方法,如果還沒有就會報錯。但如果子類有這個方法,那么就是直接調(diào)用子類的方法,即使父類有,也不去調(diào)用("地頭蛇原則")。

多態(tài)

多態(tài)的概念以及基本使用

多態(tài)是指多種形態(tài),當去完成某個行為時,不同的對象可能會產(chǎn)生不同的形態(tài)。

例如,我們在類和對象中說的小故事:當劉建明 與 陳永仁 遇到 韓琛 時,兩人打招呼的方式不一樣,這就是不同對象 在 完成同一個行為時,兩者所產(chǎn)生的形態(tài)不同。

再比如,我們每天都會吃早餐,但是不同的人 在 面對這件事情時,所表現(xiàn)出的行為就不一樣,A 可能吃面條,B可能吃包子、餃子,C可能吃大米飯等。

Python中的多態(tài)與Java、C++不同,Python中的多態(tài)只需要滿足有該方法,然后讓不同的對象去調(diào)用即可,而 Java 中的多態(tài)需要滿足三個條件:向上轉(zhuǎn)型(父類引用指向子類對象)、子類重寫父類的方法、向上轉(zhuǎn)型的父類調(diào)用該方法(被重寫的方法),這時就不再是調(diào)用父類的方法,而是調(diào)用子類的方法。但 Python中,只要這兩個類有相同的方法,當兩者賦值給同一個對象時,去調(diào)用同一個方法就會表現(xiàn)出不同的行為。

其實,多態(tài)就是表層對象一樣,內(nèi)部實際的對象不一樣,那么在調(diào)用同一個方法時,雖然看似是這個表層的對象所調(diào)用的,但實際是內(nèi)部的對象所調(diào)用并執(zhí)行的。

代碼演示:

class Animal():
    def eat(self):
        print('在玩飛盤')


class Person():
    def eat(self):
        print('到處溜達')


class Dog():
    def eat(self):
        print('瘋狂奔跑')


class Cat():
    def eat(self):
        print('偷吃罐頭')


# 定義一個函數(shù),傳入obj對象,并調(diào)用該對象的eat方法
def eat(obj):
    obj.eat()


# 方法得通過類或者對象去"."調(diào)用,而函數(shù)是直接傳參調(diào)用,不要弄混了
eat(Animal())  # 這里需要傳入對象,即:類名()
eat(Person())
eat(Dog())
eat(Cat())

運行結(jié)果:

Python初始 - 面向?qū)ο笕筇卣鱛父類_06

總結(jié)

到此這篇關(guān)于Python面向?qū)ο笕筇卣鳎豪^承、封裝(隱藏)、多態(tài)的文章就介紹到這了,更多相關(guān)Python面向?qū)ο笕筇卣鲀?nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論