Python_面向對象的三大特徵_封裝_繼承_多態(11)

目錄:

一、封裝
二、繼承
三、多態
四、綜合案例

創作不易,各位看官,點個贊收藏、關注必回關、QAQ、您的點贊是我更新的最大動力!


一、封裝

(一)什麼是封裝

封裝,是面向對象的第一個特性,體現了對數據的有效組織和數據安全性的保護機制, 在傳統的編碼中,面向對象編程思想中的類型體現的是對數據的描述,而對象體現的則是個 體數據的展示,既然是個體數據反映的就是生活中的私有數據,就需要考慮其訪問安全性, 反應到生活中就是每個個體私有數據的保護,如圖所示:在這裏插入圖片描述
(二)封裝的基本語法

1、所有屬性私有化

python 語言在實現封裝時,一些項目規範中約定使用一個下劃線開頭的屬性爲當前對象私 有屬性,不允許外界訪問,但是一個下劃線開頭的屬性是可以被直接訪問的。
語法上兩個下劃線開頭的屬性或者方法,在外界是不允許直接訪問的。
語法上兩個下劃線開頭並且結尾的屬性有特殊的應用場合。
class Manager:
    """管理員類型"""

    def __init__(self, username, password, nickname, email, phone):
        """初始化屬性數據:所有屬性私有化"""
        self.__username = username  # 標準的私有化語法
        self.__password = password  # 標準的私有化語法
        self.__nickname = nickname  # 標準的私有化語法

2、訪問私有屬性
屬性私有化之後,給每個屬性提供訪問屬性的 get 方法和設置賦值的 set 方法,通過固 定語法的格式提供給對象外部的調用者

  • 一般訪問 str
#屬性私有化之前,用戶信息可以直接訪問並修改
class User:
    """用戶類型"""
    def __init__(self,name,age):
        """用戶姓名和年齡"""
        self.name = name
        self.age = age
    def __str__(self):
        """打印用戶信息"""
        return f"我叫{self.name},今年{self.age}歲"

user = User("小明",23)
print(user)
  • 使用setter和getter訪問
    def set__username(self, username):
        """給私有屬性設置數據的方法"""
        self.__username = username

    def get__username(self):
        """獲取私有屬性數據的方法"""
        return self.__username
  • 使用限定條件訪問

作用:就是在開發過程中保護核心代碼,在類的外部不能使用(對象不能調用私有方法)
3、私有方法

class A:
    def __test1(self):
        print("--in test1--")

    def test2(self):
        self.__test1()
        print("--in test2--")
a = A()
# a.__test1() #對象不能調用私有方法
a.test2()

4、私有屬性修改

class User:
    """用戶類型"""
    def __init__(self,name,age):
        """用戶姓名和年齡"""
        # self.name = name
        # self.age = age
        self.__name = name
        self.__age = age

    def __str__(self):
        """打印用戶信息"""
        # return f"我叫{self.name},今年{self.age}歲"
        return f"我叫{self.__name},今年{self.__age}歲"
user = User("小明",23)
# print(user)
#屬性私有化之前,對象的屬性如下
# print(user.__dict__) #{'name': '小明', 'age': 23}
# user.name = "穩穩" #可以修改


#屬性私有化之後,對象的屬性如下
print(user.__dict__) #{'_User__name': '小明', '_User__age': 23}
# user.__name = "穩穩" #只是增加屬性
# print(user.__dict__)

user._User__name = "穩穩"
print(user)

返回文章目錄

二、繼承

(一)什麼是繼承
讓類與類之間產生父子關係,子類可以擁有父類的屬性和方法(私有屬性和私有方法無法繼承)
父類 用於被繼承的類,稱爲父類,也叫基類,或者超類
子類 繼承其它類的類,稱爲子類,也叫派生類
查看繼承父類的 _ base_()

繼承的作用: 可以提高代碼的複用率

(二)繼承的基本語法

"""
繼承的基本語法
    父類:被繼承的類型,需要重複利用的代碼包含在父類中
    子類:當前類型,繼承其他類型,重複使用其他類型中的代碼

    python中的所有類型都是直接或者間接繼承自object
    都是從object派生出來的!
    子類繼承父類,父類派生子類!
"""


class Father:
    """父親類型"""

    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age

    def sleep(self):
        print("睡覺時間到了,準備午休..")

    def study(self):
        print("充電時間到了,準備學習..")


class Son(Father):
    """兒子類型:繼承父親類型"""
    pass


tom = Son("湯姆", "男", 18)
print(tom.name, tom.age, tom.gender)
tom.study()
tom.sleep()

複用性體現 [使用父類的屬性]:

"""
繼承中父類的代碼的複用
"""
class Animal:
    """動物類型"""

    def __init__(self, nickname, amtype):
        self.nickname = nickname
        self.amtype = amtype

    def move(self):
        print("某個動物在運動中...")


class Beast(Animal):
    """地上跑的"""
    pass


class Bird(Animal):
    """天上飛的"""
    pass


class Fish(Animal):
    """水裏遊的"""
    pass


cat = Beast("湯姆貓", "走獸")
beita = Bird("開飛機的貝塔", "飛禽")
xiaolu = Fish("水裏的美人魚", "游魚")

cat.move()
beita.move()
xiaolu.move()

複用性高級[使用父類的屬性,自己定義自己的屬性]:

"""
繼承中父類的代碼的複用升級
從一個問題說起:
    直接使用父類不好嗎?爲什麼要寫那麼多子類的空代碼?
    靈機一動:難道爲了一行代碼一塊錢?

① 通過子類繼承父類
    子類能更好的更精確的描述生活中的某個對象
    貓 = 動物()
    貓 = 走獸()  更加準確
② 通過子類繼承父類
    子類在複用父類代碼的情況下,能擴展自己的屬性
    父類的每個子類,都有互相不同的地方~
    所以纔將多個子類相同的代碼聲明在父類中複用
    子類中互不相同的代碼保留在自己子類中使用
"""
class Animal:
    """動物類型"""

    def __init__(self, nickname, amtype):
        self.nickname = nickname
        self.amtype = amtype

    def move(self):
        print("某個動物在運動中...")


class Beast(Animal):
    """地上跑的"""

    def __init__(self, nickname, amtype, blood):
        # 子類如果一旦編寫__init__()方法
        # 就必須顯式的調用父類的__init__()方法初始化父類數據
        # Animal.__init__(nickname, amtype)
        # super(Beast, self).__init__(nickname, amtype)
        # ① 複用父類的代碼
        super().__init__(nickname, amtype)
        # ② 子類自己的代碼
        self.blood = blood


class Bird(Animal):
    """天上飛的"""

    def __init__(self, nickname, amtype, attact):
        # ① 複用父類的代碼
        super().__init__(nickname, amtype)
        # ② 子類獨有的代碼
        self.attact = attact

class Fish(Animal):
    """水裏遊的"""
    pass


cat = Beast("湯姆貓", "走獸", 2000)
beita = Bird("開飛機的貝塔", "飛禽", 100)
xiaolu = Fish("水裏的美人魚", "游魚")

print(cat.nickname, cat.amtype, cat.blood)
print(beita.nickname, beita.amtype, beita.attact)
cat.move()
beita.move()
xiaolu.move()

(三)方法覆蓋 [重寫]

簡單的來說,就是將父類裏面的方法,在子類裏面重寫

"""
方法重載:
    子類中聲明和定義了父類中相同名稱和參數的方法
"""
class Animal:
    """動物類型"""
    def __init__(self, nickname):
        self.nickname = nickname

    def move(self):
        print(f"{self.nickname}在移動中..")


class Beast(Animal):
    """走獸"""

    def move(self):
        print(f"{self.nickname}在快速的奔跑中..")


class Bird(Animal):
    """飛禽"""
    def move(self):
        print(f"{self.nickname}在愉快的飛行中..")


class Fish:
    """游魚"""
    def __init__(self, nickname):
        self.nickname = nickname

    def swimming(self):
        """移動的方法"""
        print("飛快的遊走中...")


cat = Beast("湯姆貓")
shuke = Bird("舒克的飛機")
# 調用的是同一個方法,但是執行的是不同的結果
cat.move()  # 湯姆貓在快速的奔跑中..
shuke.move()  # 舒克的飛機在愉快的飛行中..

xiaolu = Fish("小鹿")
xiaolu.swimming()
'''
通過方法重寫
① 理解繼承的代碼的重用型
② 繼承關係中,對於子類中的代碼有了一定的約束性
③ 方法覆蓋,體現了一種運行時狀態改變-體現了多態
    如果子類沒有重寫父類的方法,就直接執行父類的方法
    如果子類重寫了父類的方法,就執行子類重寫後的方法
'''

(四)子類訪問父類 [使用父類中的super()方法,三種方法]

坦克大戰:

"""
方法重載案例:坦克大戰中的坦克
"""
class Tank:
    """坦克類型"""

    def fire(self):
        print("坦克開火了,發射子彈(10行代碼)...")


class HeroTank(Tank):
    """英雄坦克:玩家控制"""

    def fire(self):
        # 子類中額外添加的功能
        print("英雄坦克,模擬玩家按下空格鍵,發射子彈[事件(按下空格動作)操作]")
        # 複用父類中發射子彈的代碼
       	# Tank.fire(self) 		  #1.父類名.方法名(self)
       	# super(Tank,self).fire() #2.super(當前類名,self).方法名()
        super().fire()		      #3.super().fire()


class EnemyTank(Tank):
    """敵方坦克:電腦控制"""

    def fire(self):
        print("添加代碼,控制坦克間隔隨機時間發射子彈")
        super().fire()


hero = HeroTank()
hero.fire()

enemy = EnemyTank()
enemy.fire()

綜合案例-寵物醫院:

"""
寵物醫院案例
    面向對象開發
"""
import time


class Pet:
    """寵物父類"""

    def __init__(self, nickname, health):
        self.nickname = nickname  # 暱稱
        self.health = health  # 健康狀態[0~30病危|30-60生病|60-80亞健康|80-100健康]

    def recovery(self):
        """康復的行爲"""
        while self.health <= 65:
            self.health += 5
            time.sleep(0.5)
            print(f"{self.health}>>正在恢復中.....")


class Hospital:
    """寵物醫院"""

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

    def care(self, pet):
        """治療的行爲"""
        # 判斷某個對象是否屬於某種類型:判斷pet對象是否Pet類型
        if isinstance(pet, Pet):
            # 醫院開始治療,用藥
            print(f"開始治療{pet.nickname}")
            # 寵物開始恢復
            pet.recovery()
        else:
            print("寵物醫院只接受寵物進行治療....")


class Cat(Pet):
    """寵物貓"""
    pass


class Dog(Pet):
    """寵物狗"""
    pass


class Person:

    def __init__(self, nickname, health):
        self.nickname = nickname
        self.health = health

    def recovery(self):
        while self.health <= 60:
            self.health += 20
            print("正在快速的恢復中...")

hospital = Hospital("瑪利亞寵物醫院")
# cat = Cat("湯姆貓", 30)
# hospital.care(cat)
# print("最終寵物的健康值:", cat.health)

dog = Dog("二哈", 20)
hospital.care(dog)
print("最終二哈的健康值:", dog.health)

# damu = Person("大牧", 50)
# hospital.care(damu)


(五)多繼承 [隔代繼承]

1、基本語法
python 語法中提供了多繼承的語法,用於體現生活中一個對象多種角色的情況,具體 語法上是將多個繼承的類型依次寫在子類聲明後面的括號中

隔代繼承:

class Animal:

    def __init__(self):
        print("我是動物")


class dog(Animal):

    pass

class cat(dog):
    pass

#創建對象
cat_tom = cat() #輸出  “我是動物”

多繼承:

"""
多繼承關係
    多繼承需要注意的問題:如果多個父類中出現了相同名稱的屬性、方法怎麼辦?
"""
class Son:
    """兒子類型"""

    def respect(self):
        """尊敬,孝順"""
        print("百善孝爲先")

    def play(self):
        print("作爲兒子角色,越快的玩耍中...")


class Husband:
    """丈夫類型"""

    def love(self):
        """恩愛的行爲"""
        print("相濡以沫")

    def play(self):
        print("作爲丈夫的角色,王者榮耀中...")


class Father:
    """老爹類型"""

    def care(self):
        """愛護的行爲"""
        print("家裏的千金,萬般呵護..")


class Teacher:
    """老師類型"""

    def teach(self):
        """授課的行爲"""
        print("前人栽樹....")


class Person(Son, Husband, Father, Teacher):
    """人的類型"""
    pass

    # def play(self):
    #     print("Person 愉快的玩耍中...")


wenwen = Person()
wenwen.play()  # Son, Husband


# # 兒子
# if isinstance(wenwen, Son):
#     wenwen.respect()
#
# # 丈夫
# if isinstance(wenwen, Husband):
#     wenwen.love()
#
# # 父親
# if isinstance(wenwen, Father):
#     wenwen.care()
#
# # 老師
# if isinstance(damu, Teacher):
#     wenwen.teach()

2、注意事項
多繼承關係中,一個類型繼承多個類型,如果在繼承的多個類型中出現了相同名稱的屬 性或者方法(當然如果出現一般都是軟件結構設計上存在問題),就會出現子類如果使用到了 這樣的屬性和方法,優先調用的是繼承的那個類型的屬性或者方法了 上述問題如果一旦出現,有兩種解決方案:

  • 重新設計軟件架構,對類型中的屬性進行規範整理
  • 梳理調用順序,按照語法語義上的順序執行

在這裏插入圖片描述
運行程序只看輸出“動物的愛”
第一種方案如果一旦實施就是常規編程,第二種方案中確定某個重複聲明的屬性的查詢 順序,可以通過規範語法進行確定,Python 提供了 mro() 方法用於確定繼承關係中屬性和方 法的查詢操作順序

class Animal:
    """動物類型"""
    def love(self):
        print("動物的愛")

class Person:
    """人的類型"""
    def love(self):
        print("人的愛")

class Tom(Animal,Person):
    pass


user_Tom = Tom()
user_Tom.love()
print(Tom.mro())

在這裏插入圖片描述
3、屬性查詢順序
Python3 中已經改善了 Python2 中多種類型操作方式(Python2/3 的區別在十五講會詳細 說明),統一了類型的聲明和加載方式,對於多繼承中的重名屬性和重名方法的查詢執行順 序,使用了廣度優先的查詢原則
在這裏插入圖片描述
(六)___init()___

這邊其實方法重寫已經提到過了
所以這邊就簡單複述下

  • 繼__init() __構建對象後屬性初始化的方法
  • 雙下劃線開頭結尾稱爲魔法方法
  • 魔法方法只會繼 承固定語法格式,如果在子類中改變了原有的語法格式的情況下,一定要主動調用父類相同 的方法初始化,否則會出現父類數據沒有初始化的問題

如果子類中沒有編寫__init__()方法,創建對象時就會自動執行繼承的默認的無參數的 init()方法,並且自動調用父類的__init__()完成初始化過程,如果所示:
在這裏插入圖片描述
如果子類中一旦編寫了自定義了__init__()方法,默認繼承的空參數的__init__()就會失效, 必須顯式的主動的調用父類的__init__()方法完成父類初始化工作,否則父類的數據就不會被 正確的繼承過來了
在這裏插入圖片描述

返回文章目錄

三、多態

(一)什麼是多態?
多態是程序運行過程中,根據運行時的數據的差異,產生不同的處理狀態,運行不同的 邏輯代碼的過程 多態作爲面向對象的特徵之一,沒有固定的語法,在經典的程序設計模式中有多種體現 方式,如策略模式中就可以根據傳遞的具體執行方案執行對應的處理結果

多態基本案例:

# 定義人類:可以調速,可以玩,在玩的過程中跳舞
# 實現多態:老年人跳廣場舞
# 多態三個條件
"""
    1.必須存在繼承關係
    2.重寫目標方法
    3.使用子類對象調用父類方法
"""

class Person:
    """人的類型"""

    def danc(self):
        print("跳舞")

    def play(self): #  self = old 老年人
        self.danc()# 老年人調用跳舞,本人含義跳舞


class OldMan(Person):
    """老年人類型"""
    def danc(self):
        print("跳廣場舞")
#
# # per1 = Person()
# # per1.play()
old = OldMan()
old.play()



策略模式
在這裏插入圖片描述
圖示中用戶需要在某網站上註冊賬號,網站動態判斷用戶的註冊方式並響應驗證 碼給正確的終端設備,在開發過程中函數式編程可以直接進行判斷處理,但是不利於程序功 能的擴展(大家可以編寫函數式的實現方式進行嘗試)。通過策略模式進行完成上述功能流程, 同時還爲將來功能的擴展預留了空間

"""
    網站可以註冊,註冊有默認的驗證碼發送方式
    分析:
        網站類
            方法:註冊方法,調用默認設備,發送驗證碼
        設備類
            方法:生成驗證碼併發送

    策略模式

"""

class WebSite:
    """網站類型"""

    def register(self,device):
        print("開始註冊")

        #調用設備發送驗證碼的方法
        device.send("6666")
        input("驗證碼已發送,請輸入")
        print("註冊成功")

class Device:
    """設備類型"""

    def send(self,code):
        print("默認發送驗證碼:",code)


class Phone(Device):
    """手機註冊"""

    def send(self,code):
        print("通過手機發送驗證碼: ",code)

class Email(Device):
    """郵箱註冊"""

    def send(self, code):
        print("通過手機發送驗證碼: ", code)

# 1 網頁註冊
# # 用戶註冊
# ws = WebSite()
# device = Device()
# # 發起註冊
# ws.register(device)

# 2 手機註冊
# 用戶註冊
ws = WebSite() # 創建對象
phone = Phone() # 實例化設備對象
# 發起註冊
ws.register(phone)


在這裏插入圖片描述

返回文章目錄

四、綜合案例

"""
學生選課管理系統
    管理員,添加課程,查看課程 [,刪除課程,修改課程]

    宗澄:課程保存課程說不通
    業務受理:增加課程,,管理員增加課程   add_course()
    邏輯處理:增刪改查數據-- 保存數據-- 課程對象~保存自己的數據 save()
"""


class Database:
    """數據庫類型:存儲項目中的所有數據"""
    # 類屬性:存儲課程-- key課程名稱:value課程對象
    courses_dict = dict()


class Users:
    """學生選課管理系統 用戶類型"""

    def __init__(self, username, password, nickname, email, phone):
        """初始化屬性數據"""
        self.username = username
        self.password = password
        self.nickname = nickname
        self.email = email
        self.phone = phone


class Manager(Users):
    """管理員類型"""
    def add_course(self):
        """增加課程的方法"""
        name = input("請輸入課程名稱:")
        if name in Database.courses_dict:
            print("課程已經存在,請使用其他名稱添加")
            return self.add_course()
        teacher = input("請輸入授課老師:")
        maxsize = input("請輸入人數上限:")
        times = input("請輸入課程課時:")
        score = input("請輸入課程學分:")
        desc = input("請輸入課程描述:")
        # 創建課程對象
        course = Course(name, teacher, maxsize, times, score, desc)
        # 保存課程數據
        course.save()
        input("課程添加完成,按任意鍵繼續。")

    def check_course(self):
        """查詢課程的方法"""
        # TODO 待完善
        for name, course in Database.courses_dict.items():
            print(f"課程名稱:{name}, 課程:{course}")
        input("課程查看完成,按任意鍵繼續")

    def update_course(self):
        """修改課程信息的方法"""
        name = input("請輸入課程名稱:")
        if name not in Database.courses_dict:
            print("課程不存在,請重新輸入")
            return self.update_course()
        # 獲取到要修改的課程數據
        course = Database.courses_dict.get(name)
        # 修改數據
        teacher = input("請輸入授課老師:")
        maxsize = input("請輸入人數上限:")
        times = input("請輸入課程課時:")
        score = input("請輸入課程學分:")
        desc = input("請輸入課程描述:")
        # 保存課程數據
        course.update()
        input("課程修改完成,按任意鍵繼續。")

    def delete_course(self):
        """刪除課程的方法"""
        name = input("請輸入要刪除的課程名稱:")
        if name not in Database.courses_dict:
            print("要刪除的課程不存在,按任意鍵重新輸入")
            return self.delete_course()
        # 直接刪除課程:直接從字典中根據課程key刪除了鍵值對
        Database.courses_dict.pop(name)
        input("課程刪除完成,按任意鍵繼續。")


class Course:
    """課程類型"""

    def __init__(self, name, teacher, maxsize, times, score, desc):
        self.name = name  # 課程名稱
        self.teacher = teacher  # 授課老師
        self.maxsize = maxsize  # 選擇人數限制
        self.times = times  # 授課課時
        self.score = score  # 課程學分
        self.desc = desc  # 課程描述

    def save(self):
        """保存課程數據"""
        Database.courses_dict[self.name] = self

    def update(self):
        """修改課程數據"""
        # 重新保存數據時,因爲key沒有變化,所以新的數據會覆蓋舊的數據
        self.save()

    def delete(self):
        """刪除課程"""
        # 通過key刪除字典中的一個鍵值對
        Database.courses_dict.pop(self.name)

    def __str__(self):
        return f"課程[名稱:{self.name}, 老師:{self.teacher},描述:{self.desc}]"


# 創建管理員對象
manager = Manager("wenwen", "123", "穩穩", "[email protected]", "15666666666")
# 添加課程
manager.add_course()

# 查看課程
manager.check_course()



返回文章目錄

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