Python學習面向對象1--封裝,繼承,多態

上次我們說到,關於python面向對象
面向對象是什麼
面向對象和麪向過程的區別
類和對象
python中如何定義類和實例化對象
類的屬性和方法

這裏我們講面向對象的特徵:封裝,繼承,多態,三大特徵。
也有說抽象加在一起算作是四大特徵,這一觀點並未得到公認。

封裝

什麼是封裝?

廣義的封裝:將事物的細節進行封起,提供好用的方法供使用者使用。
面向對象的封裝:
1.將類的屬性和方法封裝成一個或者多個類,使用的時候調用對象的屬性和方法。
2.將類的屬性進行封裝(私有化private),僅供類內部進行訪問,提供公開的方法(getter和setter)進行訪問。

python中如何實現封裝

對於上面的第二點,纔是面向對象封裝特性的重點。
請看下面這段代碼:

# -*- coding: utf-8 -*-

class Richman:
    
    def __init__(self):
        self.money = 1000000
        self.company = "alibaba"

        
    def speak(self):
        print("我對錢沒有興趣!")
        print("一個月一塊錢的工資!")
    
if __name__ == "__main__":
    rich1 = Richman()
    print(rich1.money)
    rich1.money = 1000
    print(rich1.moneyA)

運行結果如下,可以看到可以直接訪問對象的屬性和修改屬性,這樣是極爲不好的,不符合封裝的特性。
在這裏插入圖片描述
如何修改呢,將屬性進行私有化。

class Richman:
    
    def __init__(self):
        self.__money = 1000000
        self.__company = "alibaba"#__屬性即是私有屬性。

        
    def speak(self):
        print("我對錢沒有興趣!")
        print("一個月一塊錢的工資!")
    
if __name__ == "__main__":
    rich1 = Richman()
    print(rich1.money)
    rich1.money = 1000
    print(rich1.moneyA)

修改爲私有屬性,則無法進行訪問,如要進行訪問則需要對外界提供公開的方法。
在這裏插入圖片描述
同理,屬性可以私有,方法同樣可以私有。

三種封裝訪問方式

上面說到封裝特性的時候,採用getter,和setter進行提供公開的訪問
1.getter和setter

class people:
    
    def __init__(self,name,age,gender):
        self.__name = name
        self.__age = age
        self.__gender = gender
        
    def __str__(self):
        return "name = "+ self.__name +",age = "+ self.__age
    
    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        self.__age = age

if __name__ == "__main__":
    p1 = people("xuhaobo","18","男")
    print(p1.get_name())
    print(p1.get_age())
    print(p1)
    p1.set_name("wangwang")
    p1.set_age("20")
    print(p1)

提供了getter和setter可以對私有屬性進行訪問和修改。
在這裏插入圖片描述
2.將訪問方法再進行封裝,讓用戶感覺沒有變化。
使用property方法
如下的:將之間的方法再提供給用戶。用戶使用起來沒有變化,get在前,set在後
name = property(get_name,set_name)
age = property(get_age,set_age)

class people:
    
    def __init__(self,name,age,gender):
        self.__name = name
        self.__age = age
        self.__gender = gender
        
    def __str__(self):
        return "name = "+ self.__name +",age = "+ self.__age
    
    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        self.__age = age

	name = property(get_name,set_name)
    age = property(get_age,set_age)

if __name__ == "__main__":
    p1 = people("xuhaobo","18","男")
    print(p1.name)
    print(p1.age)
    print(p1)
    p1.name = "wangwang"
    p1.age = "20"
    print(p1)

可以看到用戶訪問起來並沒有覺得有任何不同。
在這裏插入圖片描述

3.使用property裝飾器
可以說是property(get,set)的變式寫法
將property()寫爲如下形式:

	@property #裝飾器
    def gender(self):
        return self.__gender
    
    @gender.setter #一般使用私有屬性的名稱作爲@的值
    def gender(self,gender):
        self.__gender = gender

代碼如下:

class people:
    
    def __init__(self,name,age,gender):
        self.__name = name
        self.__age = age
        self.__gender = gender
        
    def __str__(self):
        return "name = "+ self.__name +",age = "+ self.__age
    
    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        self.__age = age

        
#property(get,set)的變式寫法        
    @property 
    def gender(self):
        return self.__gender
    
    @gender.setter
    def gender(self,gender):
        self.__gender = gender

    
    name = property(get_name,set_name)
    age = property(get_age,set_age)
    
    
if __name__ == "__main__":
    p1 = people("xuhaobo","18","男")
    print(p1.name)
    print(p1.age)
    print(p1)
    p1.name = "wangwang"
    p1.age = "20"
    print(p1)
    print(p1.gender)
    p1.gender = "女"
    print(p1.gender)
    print(p1)

在這裏插入圖片描述
故在定義類之時,一定要進行對類進行封裝,私有化其屬性,再提供公開的get和set進行訪問。具有一定安全性。

繼承

繼承是什麼?下一代獲得上一代遺留的東西的過程稱爲繼承。
在python之中,一個類如何繼承另一個類呢,我通過代碼進行演示。

class Richman:
    
    def __init__(self):
        self.money = 1000000
        self.mompany = "alibaba"

        
    def speak(self):
        print("我對錢沒有興趣!")
        print("一個月一塊錢的工資!")

class Son(Richman):
    
    pass
    
if __name__ == "__main__":
    s1 = Son()
    print(s1.money)
    s1.money = 1000
    print(s1.money)
    s1.speak()

在這裏插入圖片描述
可以看到,son類中什麼內容也沒有寫,是繼承了richman中的屬性和方法。
下面我將money屬性改爲私有,可以看到報錯。
self.__money = 1000000
在這裏插入圖片描述
是因爲繼承只能繼承公開的屬性和方法,私有屬性和方法無法繼承

重寫override

如果對繼承的方法不滿意怎麼辦,不合適,那麼就需要對方法進行重寫。

class Richman:
    
    def __init__(self):
        self.__money = 1000000
        self.mompany = "alibaba"

        
    def speak(self):
        print("我對錢沒有興趣!")
        print("一個月一塊錢的工資!")
        
    def working(self):
        print("A你是個好同志,做事我放心!")
        print("B你是個lowB,幹事不好!")        
    
class Son(Richman):
    def working(self):
        print("還是自己人來好一點!,我把自己兄弟叫來")
    
if __name__ == "__main__":
    s1 = Son()
    r1 = Richman()
    s1.speak()
    r1.speak()
    s1.working()
    r1.working()

對父類的working方法進行了重寫,可以看到重寫後則就是調用的是重寫後在該類中的working,父類和子類中的方法,調用時是就近原則。
在這裏插入圖片描述

一道常見的面試題:

Python中有函數重載和方法重寫嗎?
答案:沒有函數重載,有方法重寫。
why:
overload:名稱相同,參數不同或者類型不同的一些函數。
1.由於python是弱數據類型語言,則類型不會不相同,
2.由於py是解釋型語言,執行時候後者所謂重載的函數會覆蓋之前的函數,則沒有重載。
重寫就不用說了,上面演示的就是重寫

繼承的作用和目的是爲了:代碼複用和多態。代碼複用是繼承的本質。

super關鍵字和多繼承

同樣是面向對象,java不支持多繼承。
py如何支持多繼承的呢?
如 class Son(Richman,xxx,xxxx,…)一個類可以有多個父類。
這有一個問題:同時繼承多個類,類中都用同一個方法,該如何調用呢?
在py3中現在使用的是新式類,採用廣度優先,即繼承的順序來調用。
在舊式類中,採用的是深度優先,按照繼承的類的深度來調用,如果深度想同,則再按照繼承順序。

super ,超級的意思,----》算是個指針,指向父類。
在子類中使用。
super().方法名()
使用如下:

# -*- coding: utf-8 -*-

class Richman:
    
    def __init__(self):
        self.__money = 1000000
        self.mompany = "alibaba"

        
    def speak(self):
        print("我對錢沒有興趣!")
        print("一個月一塊錢的工資!")
        
    def working(self):
        print("A你是個好同志,做事我放心!")
        print("B你是個lowB,幹事不好!")        
    
class Son(Richman):
    def working(self):
        print("還是自己人來好一點!,我把自己兄弟叫來")
    def test(self):
        super().working()
if __name__ == "__main__":
    s1 = Son()
    r1 = Richman()
    s1.speak()
    r1.speak()
    s1.working()
    r1.working()
    s1.test()

結果:
在這裏插入圖片描述
在初始化函數的時候,是對子類操作,不像其他語言。如下:

class RichMan:
    def __init__(self):
        print("這是父類!")
        
class Son(RichMan):
    def __init__(self):
        print("這是子類!")
        
        
if __name__ == "__main__":
    s1 = Son()

代碼執行:
在這裏插入圖片描述
如果需要調用父類,則需要使用super。

class RichMan:
    def __init__(self):
        print("這是父類!")
        
class Son(RichMan):
    def __init__(self):
        super().__init__()
        print("這是子類!")
        
        
if __name__ == "__main__":
    s1 = Son()

在這裏插入圖片描述
super()調用的方法中是有參則傳參。

多態

何爲多態?
對象的多種狀態。
在繼承的基礎上,父類引用指向子類實例的現象,稱爲多態。
比如java中父類list,一個子類arraylist。

List ls = new ArrayList()

父類調用子類方法,而py是弱數據類型,上面例子成爲:

ls = ArrayList()

由於py是弱數據類型,天生就是支持多態的,則其不關心多態的問題。
這裏就不多講了。

今天的分享就到這裏了,喜歡的小夥伴可以點贊和關注呀!博主持續分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章