python中的類與對象(3)

目錄

一. 類的多繼承

二. 類的封裝

三. 類的多態

四. 類與對象綜合練習:校園管理系統


一. 類的多繼承

在(2)第四節中我們介紹了什么是類的繼承,在子類的括號里面寫入要繼承的父類名。上一節我們只在括號內寫了一個父類名,但其實寫入多個也是可以的,這說明它同時繼承了多個父類,這就是多繼承。給出一段代碼示例如下:

class Shenxian:def fly(self):print("神仙在飛...")class Monkey:def eat_peach(self):print("猴子在偷吃仙桃...")class Sunhouzi(Shenxian, Monkey):def fangendou(self):print("孫悟空在翻跟斗...")S = Sunhouzi()
S.eat_peach()

這里Sunhouzi就同時繼承了Shenxian和Monkey類,孫猴子也具有Shenxian和Monkey的方法。這段代碼也印證了,如果子類沒有的方法,就要去父類里面尋找同名方法。在多繼承的條件下,如果多個父類都有同名方法,它首先去尋找哪個父類下的同名方法呢?

class Shenxian:def fly(self):print("神仙在飛...")def fight(self):print("神仙在打架...") class Monkey:def eat_peach(self):print("猴子在偷吃仙桃...")def fight(self):print("猴子在打架...")class Sunhouzi(Monkey, Shenxian):def fangendou(self):print("孫悟空在翻跟斗...")S = Sunhouzi()
S.fight()  # 猴子在打架...

可見它是按照括號內的順序調用的,從左往右發現某父類有就直接調用該父類下的方法。

現在我們考慮更復雜的情況:把Monkey類下的fight下方法刪除,同時寫一個Organism類,讓Shenxian和Monkey類都繼承Organism類。此時相當于多重繼承:Sunhouzi類繼承了Shenxian和Monkey類,Shenxian和Monkey類又繼承Organism類:

class Organism:def fight(self):print("群魔亂舞,各種生物都在打架...")class Shenxian(Organism):def fly(self):print("神仙在飛...")def fight(self):print("神仙在打架...") class Monkey(Organism):def eat_peach(self):print("猴子在偷吃仙桃...")class Sunhouzi(Shenxian, Monkey):def fangendou(self):print("孫悟空在翻跟斗...")S = Sunhouzi()
S.fight()  # 神仙在打架...

此時我們再讓孫猴子打架,得到的輸出是“神仙在打架...”

表面上來看,這類似于圖的廣度優先遍歷(關于什么是圖的廣度優先遍歷和深度優先遍歷,可以參考數據結構博客:20.圖的遍歷-CSDN博客),然而實際上多重繼承時確定子類繼承哪一個父類方法用的是C3算法。C3算法實現了三種重要特性:

  • 保持繼承拓撲圖的一致性。
  • 保證局部優先原則(比如A繼承C,C繼承B,那么A讀取父類方法,應該優先使用C的方法而不是B的方法)。
  • 保證單調性原則(即子類不改變父類的方法搜索順序)。

我們并不去詳細介紹C3算法(因為沒有開發人員這么去干),只給出一段代碼說明多重繼承時既不滿足廣度優先遍歷也不滿足深度優先遍歷:

class A:def test(self):print("from A")class B(A):passclass B2:def test(self):print("from B2")class C(A):def test(self):print("from C")class C2:def test(self):print("from C2")class D(B, B2):passclass E(C, C2):passclass F(D, E):passf1 = F()
f1.test()
# from C

用C3方法解析的順序即方法解析順序(Method Resolution Order,MRO),我們可以用mro()查看,這樣我們不需要懂C3算法也可以知道它的方法解析順序:

print(F.mro()) 
# [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.B2'>, <class '__main__.C2'>, <class 'object'>]

二. 類的封裝

封裝可以被認為是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問要訪問該類的代碼和數據,必須通過嚴格的接口控制。封裝最主要的功能在于我們能修改自己的實現代碼,而不用修改那些調用我們代碼的程序片段。適當的封裝可以讓程式碼更容易理解與維護,也加強了代碼數據的安全性。封裝的優點如下:

  1. 良好的封裝能夠減少耦合。
  2. 類內部的結構可以自由修改。
  3. 可以對成員變量進行更精確的控制。
  4. 隱藏信息,實現細節。

封裝的原則是:

  1. 將不需要對外提供的內容都隱藏起來;
  2. 把屬性都隱藏,提供公共方法對其訪問。

以下是一個沒有封裝的例子,我們可以不打槍就使得人的血量發生減少:

class Person:def __init__(self, name, sex):self.name = nameself.sex = sexself.life_val = 100a = Person("zhangsan", "M")
a.life_val = 50
print(a.life_val)  # 50

為了解決這個問題我們需要對變量進行私有化,即加__,此時在外部是無法訪問私有屬性life_val的:

class Person:def __init__(self, name, sex):self.name = name  # 實例變量,成員變量self.sex = sexself.__life_val = 100  # 私有變量,私有屬性,加__使得變量私有化a = Person("zhangsan", "M")
print(a.__life_val)  
# AttributeError: 'Person' object has no attribute '__life_val'

但是私有屬性在類的內部是可以被訪問的,如:

class Person:def __init__(self, name, sex):self.name = nameself.sex = sexself.__life_val = 100  def get_life_val(self):print("生命值還有:", self.__life_val)def got_attack(self):self.__life_val -= 20print("[%s]受到了攻擊,掉了20滴血,現在生命值是[%s]" % (self.name, self.__life_val))a = Person("zhangsan", "M")
a.get_life_val()  # 生命值還有: 100
a.got_attack()  # [zhangsan]受到了攻擊,掉了20滴血,現在生命值是[80]
a.get_life_val()  # 生命值還有: 80

如此我們就可以讓life_val只讀,而不能對其進行外部修改。

同理,我們也可以對方法進行封裝,只在類的內部進行調用:

class Person:def __init__(self, name, sex):self.name = nameself.sex = sexself.__life_val = 100  def __breath(self):print(self.name,"在呼吸...")a = Person("zhangsan", "M")
a.__breath()  # AttributeError: 'Person' object has no attribute '__breath'

如果非要在外部進行訪問,則需要寫:實例對象._類名+方法名,相當于解封裝:

class Person:def __init__(self, name, sex):self.name = name  # 實例變量,成員變量self.sex = sexself.__life_val = 100  # 私有變量,私有屬性,加__使得變量私有化a = Person("zhangsan", "M")
print(a._Person__life_val)  # 100
# 如果直接寫print(a.__life_val),則會報AttributeError

三. 類的多態

有時一個對象會有多種表現形式,比如網站頁面有個button按鈕,這個button的設計可以不一樣(單選框、多選框、圓角的點擊按鈕、直角的點擊按鈕等),盡管長的不一樣,但它們都有一個共同調用方式,就是onClick()方法。我們直要在頁面上一點擊就會觸發這個方法。點完后有的按鈕會變成選中狀態、有的會提交表單、有的甚至會彈窗。這種多個對象共用同一個接口,又表現的形態不一樣的現象,就叫做多態(Polymmorphism)。

Polymorphilsm is based on the greek words Poly (many) and morphism(forms), 接下來我們通過代碼來演示什么是多態。

(1)通過統一函數接口實現多態

class Dog():def sound(self):print("汪汪汪...")class Cat():def sound(self):print("喵喵喵...")def make_sound(animal):animal.sound()dog = Dog()
cat = Cat()
make_sound(cat)  # 喵喵喵...
make_sound(dog)  # 汪汪汪...

(2)通過抽象類實現多態(最常用)

假如你開發一個文本編輯器,支持多種文檔類型, 在用戶通過你的編輯器打開文件之前,你也不知道準備要打開的是什么類型的文件,可能是pdf,也可能是word。
假如你為每個文件類型都寫一個類,每個類都通過show()方法來調用打開對應的文檔,為了確保每個類都必須實現show()方法,你可以寫一個抽象類Document:

class Document():def __init__(self, name):self.name = namedef show(self):raise NotImplementedError("Subclass must implement abstract method")class Pdf(Document):def show(self):print("Show Pdf contents!")class Word(Document):def show(self):print("Show Word contents!")pdf = Pdf("1.pdf")
word = Word("2.doc")
obj = [pdf, word]
for o in obj:o.show()

四. 類與對象綜合練習:校園管理系統

設計一個培訓機構管理系統,有總部、分校,有學員、老師、員工,實現具體如下需求:
1.有多個課程,課程要有定價
2.有多個班級,班級跟課程有關聯
3.有多個學生,學生報名班級,交這個班級對應的課程的費用
4.有多個老師,可以分布在不同校區,上不同班級的課
5.有多個員工,可以分布在不同校區在總部可以統計各校區的賬戶余額、員工人數、學員人數
6.學生可以轉校、退學

隨便瞎寫了一個,可能略有出入,如有語法錯誤歡迎指正!

(此部分建議先自己動手寫,如果寫不出來再去看別人的代碼)

class School():def __init__(self, name, address):self.name = nameself.address = addressself.branches = set()self.stuff = set()self.classes = set()def print_address(self):print("學校[%s]的地址是[%s]" % (self.name, self.address))def print_classes(self):print("學校[%s]目前所開班型有:" % self.name)for i in self.classes:print(i.class_name)def print_branches(self):print("學校[%s]目前的分校有:" % self.name)for i in self.branches:print(i.name)def print_stuff(self):print("學校[%s]目前的雇員有:" % self.name)for i in self.stuff:print(i.name)def pay_roll(self):self.count_teacher_num()self.count_stuff_num()money = 0for i in self.stuff:money += i.salaryfor i in self.classes:money += i.teacher.salaryprint("總校應發工資:%s" % money)for i in self.branches:for j in i.stuff:    money += j.salaryfor j in i.classes:money += j.teacher.salaryprint("總校分校合計應發工資:%s" % money)def count_teacher_num(self):teacher_num = len(self.classes)for i in self.branches:teacher_num += len(i.classes)print("[%s]有教師數量[%s]"%(self.name, teacher_num))def count_stuff_num(self):stuff_num = len(self.stuff)for i in self.branches:stuff_num += len(i.stuff)print("[%s]有職工數量[%s]"%(self.name, stuff_num))def count_stu_num(self):stu_num = 0for i in self.classes:stu_num += len(i.student)for i in self.branches:for j in i.classes:stu_num += len(j.student)print("[%s]有學生數量[%s]"%(self.name, stu_num))class BranchSchool():def __init__(self, name, address, headquater):self.name = nameself.address = addressself.headquater = headquaterheadquater.branches.add(self)self.classes = set()self.stuff = set()def print_address(self):print("學校[%s]的地址是[%s]" % (self.name, self.address))def print_classes(self):print("學校[%s]目前所開班型有:" % self.name)for i in self.classes:print(i.class_name)def print_stuff(self):print("學校[%s]目前的雇員有:" % self.name)for i in self.stuff:print(i.name)class Kecheng():def __init__(self, class_name, class_id, price, num_period, branchschool):self.class_name = class_nameself.class_id = class_idself.price = priceself.num_period = num_periodself.student = set()self.branchschool = branchschoolbranchschool.classes.add(self)self.teacher = Nonedef print_class_information(self):if self.teacher == None:print("本課程未指定授課教師,請調用教師類方法指定授課教師!")else:print("[%s]課程基本信息:" % self.class_name)print("課序號:[%s]" % self.class_id)print("開課校區:[%s]" % self.branchschool.name)print("授課教師:[%s]" % self.teacher.name)print("本課程學時:[%s]" % self.num_period)def print_student(self):self.print_class_information()print("-------本課程學生名單----------")for i in self.student:print(i.name,i.student_id)class Student():def __init__(self, name, student_id):self.name = nameself.student_id = student_idself.kecheng = Nonedef join_class(self, kecheng):self.kecheng = kechengself.Number_of_hours_attended = 0kecheng.student.add(self)print("學生[%s]選報了[%s]課程,課序號:[%s]" % (self.name, kecheng.class_name, kecheng.class_id))def print_information(self):print("學生[%s], 學號[%s]" % (self.name, self.student_id))if self.kecheng == None:print("該生沒有選報課程!")else:print("該生所上課程[%s], 已上課時數[%s]" % (self.kecheng.class_name, self.Number_of_hours_attended))def shangke(self):self.Number_of_hours_attended += 1print("學生[%s]來上課了,已上課時數[%s]" % (self.name, self.Number_of_hours_attended))def tuixue(self):shengyuxueshi = self.kecheng.num_period - self.Number_of_hours_attendedmoney = shengyuxueshi * self.kecheng.priceprint("學生[%s]退課了,剩余課時數[%s],應退學費[%s]元" % (self.name, shengyuxueshi, money))self.kecheng.student.remove(self)class Teacher():def __init__(self, name, salary, teacher_id):self.name = nameself.salary = salaryself.kecheng = Noneself.teacher_id = teacher_iddef print_information(self):print("教師[%s], 教師工作證號[%s]" % (self.name, self.teacher_id))if self.kecheng == None:print("該老師不執教任何課程!")else:print("該老師所上課程[%s]" % (self.kecheng.name))def join_class(self, kecheng):self.kecheng = kechengkecheng.teacher = selfprint("教師[%s]成為課程[%s]的教師!課序號[%s]" % (self.name, kecheng.class_name, kecheng.class_id))class Stuff():def __init__(self, name, salary, stuff_id):self.name = nameself.salary = salaryself.stuff_id = stuff_idself.school = Nonedef print_information(self):print("雇員[%s], 工作證號[%s]" % (self.name, self.stuff_id))if self.school == None:print("該雇員還沒有分配校區!")else:print("所在校區[%s]" % (self.school.name))def join_school(self, school):self.school = schoolprint("雇員[%s]加入[%s]校區" % (self.name, school.name))school.stuff.add(self)school1 = School("北京總校", "北京市海淀區清華大學")
branchschool1 = BranchSchool("北京分校", "北京站1號", school1)
school2 = School("上海總校", "上海市黃浦區南京東路1號")
branchschool2 = BranchSchool("上海分校", "虹橋火車站", school2)
branchschool3 = BranchSchool("上海第二分校", "松江大學城", school2)
student1 = Student("張三", 4312784)
student2 = Student("李四", 4371289)
student3 = Student("王五", 6578584)
student4 = Student("趙八", 3421554)
student5 = Student("曹一", 1254265)
student6 = Student("操日本", 9432713)
teacher1 = Teacher("趙老憨", 15000, 5478238)
teacher2 = Teacher("李老師", 18000, 8033427)
kecheng1 = Kecheng("數據結構", 548792, 500, 45, school1)
kecheng2 = Kecheng("計算機組成原理", 431287, 500, 45, branchschool1)
stuff1 = Stuff("王瑩", 20000, 412379)
stuff2 = Stuff("趙鵬", 1000, 4127982)
stuff3 = Stuff("李麻瓜", 2000, 5189312)
school2.print_branches()
school1.print_classes()
student1.print_information()
branchschool1.print_classes()
student1.join_class(kecheng1)
student2.join_class(kecheng2)
student3.join_class(kecheng1)
teacher1.join_class(kecheng1)
teacher2.join_class(kecheng2)
kecheng1.print_student()
school1.count_stu_num()
student1.print_information()
student1.shangke()
student1.shangke()
student1.tuixue()
stuff1.join_school(school1)
stuff2.join_school(branchschool1)
stuff3.join_school(school2)
school1.print_stuff()
school1.pay_roll()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718732.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718732.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718732.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

新手淘寶開店如何引流

對于新手淘寶賣家來說&#xff0c;引流是開店過程中最為關鍵的一環。如何吸引潛在客戶進入店鋪&#xff0c;提高商品的曝光率和銷量&#xff0c;是每個新手賣家都面臨的挑戰。本文將為你提供新手淘寶開店的引流攻略&#xff0c;幫助你從零開始掌握實用的引流技巧。 一、優化店…

C++的類型轉換

1.C語言中的類型轉換 在C語言中&#xff0c;如果賦值運算符左右兩側類型不同&#xff0c;或者形參與實參類型不匹配&#xff0c;或者返回值類型與接收返回值類型不一致時&#xff0c;就需要發生類型轉化&#xff0c;C語言中總共有兩種形式的類型轉換&#xff1a;隱式類型轉換和…

【機器人最短路徑規劃問題(柵格地圖)】基于模擬退火算法求解

代碼獲取方式&#xff1a;QQ&#xff1a;491052175 或者 私聊博主獲取 基于模擬退火算法求解機器人最短路徑規劃問題&#xff08;柵格地圖&#xff09;的仿真結果 仿真結果&#xff1a; 初始解的路徑規劃圖 收斂曲線&#xff1a; 模擬退火算法求解的路徑規劃圖 結論&#xff…

Ubuntu20安裝zabbix-agent2,對接zabbix 6.4

在Ubuntu 20.04 LTS上安裝Zabbix Agent 2并與Zabbix Server 6.4對接&#xff0c;請按照以下步驟操作&#xff1a; 更新系統&#xff1a; sudo apt update sudo apt upgrade 添加Zabbix官方倉庫&#xff1a; 首先&#xff0c;需要將Zabbix的官方存儲庫添加到你的系統中以獲取Za…

C#面:常用的 異常類 有哪些

異常類是用于處理程序運行時出現的錯誤或異常情況的類。 C# 提供了一些內置的異常類&#xff0c;常用的包括&#xff1a; System.Exception&#xff1a;所有異常類的基類&#xff0c;可以用于捕獲所有類型的異常。System.SystemException&#xff1a;表示系統級別的異常&…

【了解SpringCloud Gateway微服務網關】

曾夢想執劍走天涯&#xff0c;我是程序猿【AK】 目錄 簡述概要知識圖譜什么是SpringCloudGateway功能特征應用場景核心概念配置文件工作原理路由謂詞工廠&#xff08;內置的&#xff09;[After 路由謂詞工廠](https://docs.spring.io/spring-cloud-gateway/docs/current/refere…

Mysql運維篇(七) 部署MHA--完結

一路走來&#xff0c;所有遇到的人&#xff0c;幫助過我的、傷害過我的都是朋友&#xff0c;沒有一個是敵人。如有侵權&#xff0c;請留言&#xff0c;我及時刪除&#xff01; 一、MHA軟件構成 Manager工具包主要包括以下幾個工具&#xff1a; masterha_manger 啟…

【C++】多態深入分析

目錄 一&#xff0c;多態的原理 1&#xff0c;虛函數表與虛函數表指針 2&#xff0c;原理調用 3&#xff0c;動態綁定與靜態綁定 二&#xff0c;抽象類 三&#xff0c;單繼承和多繼承關系的虛函數表 1&#xff0c;單繼承中的虛函數表 2&#xff0c;多繼承中的虛函數表 …

“編碼迷宮中的探險者:探索程序員職業賽道的無限可能“

在這個信息技術飛速發展的時代&#xff0c;程序員的職業賽道就像是一座錯綜復雜的迷宮&#xff0c;它既充滿了挑戰&#xff0c;又蘊藏著無限的機遇。這座迷宮中&#xff0c;有前端的美麗花園&#xff0c;后端的黑暗洞穴&#xff0c;還有數據科學的神秘密室。每一條路徑都有其獨…

內網搭建mysql8.0并搭建主從復制詳細教程!!!

一、安裝mysql 1.1 mysql下載鏈接&#xff1a; https://downloads.mysql.com/archives/community/ 1.2 解壓包并創建相應的數據目錄 tar -xvf mysql-8.2.0-linux-glibc2.28-x86_64.tar.xz -C /usr/local cd /usr/local/ mv mysql-8.2.0-linux-glibc2.28-x86_64/ mysql mkdir…

Python繪圖-9餅圖(上)

餅圖&#xff08;Pie Chart&#xff09;是一種用于表示數據分類和相對大小的可視化圖形。在餅圖中&#xff0c;整個圓形代表數據的總和&#xff0c;而圓形內的各個扇形則代表不同的分類或類別&#xff0c;扇形的面積大小表示該類別在整體中所占的比例。餅圖通常用于展示數據的分…

FW, IPS, IDS

文章目錄 FW (Firewall, 防火墻)IPS (Intrusion Prevention System, 入侵防御系統)IDS (Intrusion Detection System, 入侵檢測系統)IDS vs. FWIPS FW (Firewall, 防火墻) 產品定位&#xff1a; 防火墻的主要作用是進行網絡訪問控制。它充當網絡的門衛&#xff0c;控制進入和離…

《人間值得》讀書筆記

人的一生說短不短&#xff0c;說長不長。蕓蕓眾生&#xff0c;為了生活努力的掙扎&#xff0c;太少的人能衣食無憂&#xff0c;所以我們每天為了碎銀幾兩&#xff0c;為了生活奔波。 《人間值得》的主人公是一個90歲的老奶奶&#xff0c;她的生活經歷很豐富&#xff0c;她的人…

ObjectProvider學習

簡介 ObjectProvider 是 Spring Framework 5.0 之后引入的一個新接口&#xff0c;它提供了一個靈活的方式來訪問由 Spring 容器管理的 Bean。ObjectProvider 提供了一種更加類型安全的方式來查找和注入依賴項&#xff0c;同時還支持 Null 值的處理以及延遲初始化。 ObjectProv…

Window部署Jaeger

參考&#xff1a;windows安裝使用jaeger鏈路追蹤_windows安裝jaeger-CSDN博客 下載&#xff1a;Releases jaegertracing/jaeger GitHub Jaeger – Download Jaeger 目錄 1、安裝nssm 2、安裝運行 elasticsearch 3、安裝運行 3.1部署JaegerAgent 3.2部署JaegerCollec…

【全志D1-H 哪吒開發板】Debian系統安裝調教和點燈指南

全志D1-H開發板【哪吒】使用Deabian系統入門 特別說明&#xff1a; 因為涉及到操作較多&#xff0c;博文可能會導致格式丟失 其中內容&#xff0c;會根據后續使用做優化調整 目錄&#xff1a; 參考資料固件燒錄啟動調教點燈問題 〇、參考資料 官方資料 開發板-D1開發板【…

C++:函數模板整理

函數模板: 找到函數相同的實現思路&#xff0c;區別于函數的參數類型。 使用函數模板使得函數可容納不同類型的參數實現函數功能&#xff0c;而不是當類型不同時便編譯大量類型不同的函數&#xff0c;產生大量重復代碼和內存占用 函數模板格式&#xff1a; template<typ…

[Vulnhub]靶場 Red

kali:192.168.56.104 主機發現 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 …

ARM64匯編02 - 寄存器與指令基本格式

最近的文章可能會有較多修改&#xff0c;請關注博客哦 異常級別 ARMv8處理器支持4種異常等級&#xff08;Exception Level&#xff0c;EL&#xff09;。 EL0 為非特權模式&#xff0c;用于運行應用程序&#xff0c;其他資源訪問受限&#xff0c;權限不夠。 EL1 為特權模式&…

【王道操作系統】ch1計算機系統概述-06虛擬機

文章目錄 【王道操作系統】ch1計算機系統概述-06虛擬機01傳統計算機02虛擬機的基本概念&#xff08;1&#xff09;第一類虛擬機管理程序&#xff08;2&#xff09; 第二類虛擬機管理程序&#xff08;3&#xff09; 兩類虛擬機管理程序的對比 【王道操作系統】ch1計算機系統概述…