目錄
一.進階
類方法和靜態方法
屬性(Properties)
繼承和多態
抽象基類(Abstract Base Classes - ABCs)
魔術方法(Magic Methods)
組合和聚合
使用場景
二.私有屬性
實現對數據的隱藏
設置私有屬性
添加額外對屬性操作的方法
三.私有方法
實現對方法的隱藏
直接調用私有方法所出現的問題
四.對象關聯
將兩個對象關聯
調用關聯的對象
關聯多個對象
一.進階
在Python中,面向對象編程(OOP)的進階概念允許開發者構建更復雜、更靈活和易于維護的代碼結構,以下是一些關鍵的進階特性及其應用。
類方法和靜態方法
- 類方法(class methods):?
- 使用@classmethod裝飾器定義。
- 第一個參數通常是cls,指的是類本身,而非類的實例。
- 可以訪問和修改類狀態。
- 靜態方法(static methods):?
- 使用@staticmethod裝飾器定義。
- 不需要默認的self或cls參數。
- ?主要用于在類的定義中包含一些與類相關,但在執行時不需要類或實例本身的工具函數。
屬性(Properties)
屬性允許將方法調用封裝成對屬性的訪問操作,使用@property裝飾器可以將類中的方法變為只讀屬性。
繼承和多態
- 多重繼承(multiple inheritance):?
- Python支持從多個基類繼承,這允許創建復雜的繼承結構。
- 需要注意的是多重繼承可能導致的鉆石問題(Diamond Problem)及其解決方案:方法解析順序(MRO)。
- 多態(polymorphism):?
- Python的多態性是通過鴨子類型(Duck Typing)來實現的:如果它像鴨子一樣走路和叫,那么它就是鴨子。
- 這意味著函數或方法可以接受任何類型的對象,只要這些對象提供了合適的方法或行為。
抽象基類(Abstract Base Classes - ABCs)
- 抽象基類是一種定義了一組方法和屬性的基類,但至少有一個方法是抽象的。即:該方法沒有實現,僅有聲明。
- 使用模塊abc和裝飾器@abstractmethod來定義抽象方法。
魔術方法(Magic Methods)
- 通過定義特定的方法,可以改變類的一些默認行為,這些特定方法被稱為魔術方法。如:__init__, __str__, __call__等。
- 例如:通過定義__add__方法,可以讓類的實例支持加法操作符。
組合和聚合
- 組合(composition)和聚合(aggregation)是將對象或類聯合在一起的兩種方式,通常用于實現has-a關系。
- 組合意味著一個對象完全擁有另一個對象,而聚合則允許對象有更獨立的生命周期。
使用場景
這些進階特性在許多場合都非常有用,例如:
- 設計模式的實現:單例模式、工廠模式、策略模式等。
- 構建框架或庫,封裝復雜的邏輯。
- 處理復雜的數據結構,如圖、樹,和更高級的集合類型。
- 提供API時隱藏內部實現的細節,僅暴露簡潔的接口。
掌握Python中的面向對象編程的進階概念,可以幫助開發者在編寫Python代碼時具備更高的靈活性和表達能力,構建出更加健壯、可重用和易于維護的軟件。
二.私有屬性
案例演示
class Cat:def __init__(self, new_name, new_age):self.name = new_nameself.age = new_agedef print_info(self):print("我叫%s,今年%s了" % (self.name, self.age))# 創建貓對象
cat = Cat("波斯貓", 4)
# 調用方法
cat.print_info()
# 嘗試修改屬性
cat.age = -10
# 調用方法
cat.print_info()
如果運行上述代碼,會發現,第二次輸出的信息有誤:我叫波斯貓,今年-10歲了
之所以出現這樣的錯誤,究其原因是因為:我們通過對象直接給實例屬性賦值的這種方式容易出錯
如果在賦值的時候,是通過一個實例方法的調用,在方法中對數據進行嚴格的檢查,合格的數據可以給屬性設置,不合格的數據就提醒開發者,這樣一來就能夠保證數據的準確性了。
那該怎樣實現呢?
實現對數據的隱藏
答:
1. 設置屬性為私有屬性
2. 添加額外對屬性操作的方法
設置私有屬性
在Python中,如果想要設置為私有的屬性,那么僅僅需要在定義屬性時在前面加兩個下劃線__即可
既然有了私有屬性,那對象能夠直接操作它么?
答:不能,否則就沒有私有的作用了
示例如下:
class Teacher:def __init__(self):self.name = "小明"self.__age = 18 # 這個屬性就是私有屬性t = Teacher()
print(t.name) # 能夠獲取
print(t.__age) # 此時會程序報錯,因為__age是私有屬性,不能通過對象直接操作
添加額外對屬性操作的方法
想要實現對私有屬性的操作,我們需要定義方法,在方法中操作
示例如下:
class Teacher:def __init__(self):self.name = "小明"self.__age = 18 # 這個屬性就是私有屬性def set_age(self, new_age):if 1 <= new_age <= 120:self.__age = new_ageprint("設置年齡成功")else:print("年齡數據有誤...")def get_age(self):return self.__aget = Teacher()
t.set_age(20) # 設置年齡
print(t.get_age()) # 獲取年齡
簡單總結
1.操作屬性有兩種方法:
- 直接通過對象修改:對象名.屬性名 = 數據
- 通過方法間接修改:對象名.方法名(數據)
2.通過使用方法來進行修改,就可以在方法中進行數據合法性的檢查
3.通過__可以將屬性變為私有屬性,這樣就防止了通過對象直接操作屬性時可能帶來的隱患
三.私有方法
引入
生活中我們肯定去過銀行辦理過業務,我們可以從銀行的大門進入大廳,取號等待辦理業務,可以在大廳里來回走動,這個區域是所有人都可以隨意進出的。而銀行辦公人員工作的地方,只能有相應的權限的辦公人員才能進出,這個區域對于外來辦理業務的人員來說是禁止的。
通過上述的描述,大家能夠理解了一件事情,即訪問的地方不同需要的權限不同
那么試想,一個較大軟件系統肯定有很多個可以讓用戶直接調用的接口(API可以簡單理解為方法)這些接口可以任意調用,而有些接口就不能使用。
在Python中,我們把可以通過對象直接調用的方法叫做公有方法,不能通過對象直接調用的方法叫做私有方法
實現對方法的隱藏
對于定義私有方法的方式與定義私有屬性基本相同,就是在方法的前面添加__(即兩個下劃線__)
示例如下:
class BankService:def __init__(self, money=5000):self.money = moneydef __bank_to_bank(self):if self.money >= 5000:print("這里是銀行之間的轉賬代碼...")return Trueelse:return Falsedef transfer(self):if self.money > 10000:if self.__bank_to_bank():print("轉賬成功...")else:print("轉賬失敗...")else:print("都沒錢,還轉什么啊!自己留著花吧!")bank_service = BankService(10001)
bank_service.transfer() # 可以調用,是公有方法運行測試(轉賬成功):這里是銀行之間的轉賬代碼...
轉賬成功...運行測試(轉賬失敗):都沒錢,還轉什么啊!自己留著花吧!
注意點:Python中沒有像C++中public和private這些關鍵字來區別公有和私有,它是以命名方式來區分。如果在名字前面加了兩個下劃線__,則表明該屬性是私有,否則為公有。
直接調用私有方法所出現的問題
代碼示例:
上述代碼 加入bank_service.__bank_to_bank() # 不可以調用,是私有方法運行結果:
Traceback (most recent call last):File "/Users/poppies/Documents/python_code/私有方法代碼測試.py", line 25, in <module>bank_service.__bank_to_bank() # 不可以調用,是私有方法
AttributeError: 'BankService' object has no attribute '__bank_to_bank'
四.對象關聯
概述
我們在上學的時候,每個同學是一個對象,那么教室也是一個對象。每個同學肯定是屬于某一個教室的,例如張三是爬蟲一班的。那么怎樣才能用代碼來實現他們之間的關系呢?
將兩個對象關聯
如果當前的教室對象與學生對象是沒有任何關系關聯的。如果想要實現學生屬于教室,那么只需要兩步就能實現
- 搞清楚誰屬于誰,例如上述示例中,學生屬于教室
- 在范圍大的那個對象中,定義一個屬性存儲范圍小的對象引用即可
?代碼示例:
class ClassRoom:def __init__(self, name):self.cls_name = nameclass Student:def __init__(self, name):self.stu_name = name# 創建一個教室對象
room_1 = ClassRoom("python一班")# 創建一個學生對象
stu_1 = Student("安娜")# 直接給教室對象添加屬性
room_1.stu_obj = stu_1
調用關聯的對象
上述代碼已經完成了對象學生與教室的關聯,那么怎樣調用呢?格式如下:
# 如果A對象中的某個屬性指向了B對象,那么調用方式
A.xxx # 此時就是指的B對象# 如果想要調用B對象中的某方法,那么就再接著.yyy方法即可
A.xxx.yyy()
代碼示例:
class ClassRoom:def __init__(self, name):self.cls_name = nameself.stu_obj = None # 一般情況下在本類的其它方法中用到的實例屬性,都要在__init__方法中定義def add_new_stu(self, stu):"""定義新方法用來完成關聯"""self.stu_obj = stuclass Student:def __init__(self, name):self.stu_name = name# 創建一個教室對象
room_1 = ClassRoom("python一班")# 創建一個學生對象
stu_1 = Student("安娜")# 調用方法將學生添加到對象中
room_1.add_new_stu(stu_1)# 調用學生的姓名
# 教室對象.學生.姓名
print(room_1.stu_obj.stu_name)運行結果:
安娜
關聯多個對象
既然關聯一個對象搞懂了,那么關聯多個也就手到擒來,方式如下:
- 在范圍大的那個對象中再定義一個新的屬性,通過設置屬性指向新的對象
- 如果關聯的新的對象與之前關聯的對象類型相同,可以考慮用列表、字典、集合等方式將它們關聯
實現將多個學生關聯到一個教室:
class ClassRoom:def __init__(self, name):self.cls_name = nameself.stu_list = list()def add_new_stu(self, stu):self.stu_list.append(stu)class Student:def __init__(self, name):self.stu_name = name# 創建一個教室對象
room = ClassRoom("python爬蟲班")# 創建多個學生對象
stu_1 = Student("安娜")
stu_2 = Student("小明")
stu_3 = Student("小紅")# 調用方法將學生添加到對象中
room.add_new_stu(stu_1)
room.add_new_stu(stu_2)
room.add_new_stu(stu_3)# 調用學生的姓名
# 教室對象.列表[下標].姓名
print(room.stu_list[0].stu_name)
print(room.stu_list[1].stu_name)
print(room.stu_list[2].stu_name)